10. API 参考

10.1. BPU API

10.1.1. 简介

为了方便利用 BPU 开发板提供的深度学习加速功能,我们开发了一套BPU API接口。在封装 BPU 提供的模块功能的同时,对开发者提供一套便于理解和使用的 API。

这套 API 分为两个部分,一个是针对执行深度学习模型的过程,封装了会使用到的接口;另一部分是相关的 IO 模块接口,比如 camera,pyramid 等。

BPU API 目前提供了四个头文件:

  • bpu_predict.h:提供模型运行所需要的接口声明

  • bpu_predict_entension.h:提供扩展的模型接口声明

  • bpu_io.h:提供 X2/J2 开发的 IO 模块接口声明

  • bpu_parse_utils.h:提供地平线特有的模型输出解析接口的声明

10.1.2. 深度学习模型相关接口

10.1.2.1. 相关数据结构

typedef void* BPUHandle

整个模型的 handle。所有跟 BPU 模型相关的操作通过这个 handle 来完成。

struct BPUModelInfo

模型信息数据结构,用来获取模型的输入、输出信息。

typedef void* BPU_Buffer_Handle

表示 BPU 相关操作需要的 buffer 对象。

typedef void* BPUPyramidBuffer

表示执行 BPU 金字塔操作后,返回的 buffer 对象。

struct BPUBBox

表示执行检测模型之后,解析输出得到的检测框信息。

typedef struct hb_BPU_MEMORY_S BPU_MEMORY_S

表示模型输入输出的memory结构体。

typedef enum hb_BPU_OP_TYPE_E BPU_OP_TYPE_E

表示模型输出op的类型枚举,目前仅列出卷积和其他op。

typedef enum hb_BPU_LAYOUT_E BPU_LAYOUT_E

表示模型输入输出的内存布局。

typedef enum hb_BPU_DATA_SHAPE_S BPU_DATA_SHAPE_S

表示模型输入输出的shape信息。

typedef enum hb_BPU_RUN_CTRL_S BPU_RUN_CTRL_S

表示模型运行时需要的控制结构体。

typedef enum hb_BPU_DATA_TYPE_E BPU_DATA_TYPE_E

描述各种数据类型的枚举,包括图像或者语音特征等。

typedef enum hb_BPU_MODEL_NODE_S BPU_MODEL_NODE_S

表示模型输入输出的节点信息。

typedef enum hb_BPU_MODEL_S BPU_MODEL_S

模型信息数据结构,用来获取模型的句柄以及输入输出节点信息。

typedef enum hb_BPU_TENSOR_S BPU_TENSOR_S

描述数据的类型,形状以及内存地址等信息。

typedef enum hb_BPU_GLOBAL_CONFIG_E BPU_GLOBAL_CONFIG_E

枚举了bpu api中可以设置的全局控制参数。

typedef enum hb_BPU_CONVERT_LAYOUT_METHOD_E BPU_CONVERT_LAYOUT_METHOD_E

表示转换内存布局的方法枚举。

typedef enum hb_BPU_RESIZE_CTRL_S BPU_RESIZE_CTRL_S

表示缩放图片需要的控制信息。

10.1.2.2. 全局设置接口

int HB_BPU_setGlobalConfig(BPU_GLOBAL_CONFIG_E config_key, const char *config_value)

通过key-value的方式配置全局控制信息,包含了最大任务数量,基于内存池的buffer数量以及debug模式等。

参数:

  • config_key:全局对象的枚举

  • config_value:设置全局对象的值

10.1.2.3. 模型加载的接口

模型加载接口主要是为了加载或释放编译器产出的模型文件。加载方式是显式调用 load 接口,这里先描述了两种显式调用 load 接口的方式。

int BPU_loadModel(const char* model_file_name, BPUHandle *handle, const char *bpu_config_file);

加载模型文件并返回一个 BPUHandle,这个 handle 是 void* 类型。

参数:

  • model_file_name:模型文件名称

  • handle:所加载模型的对象 handle

  • bpu_config_file:BPU API 使用的配置文件,JSON 格式

int BPU_release (BPUHandle handle);

释放 BPU Handle。这个函数通常在 APP 退出的时候调用,用于资源回收和释放。

int HB_BPU_loadModel(const void *model_data, int model_size, BPU_MODEL_S *model);

从一段内存中加载模型文件并返回一个 BPU_MODEL_S 结构体。BPU_MODEL_S结构体由外部传入,该函数直接往结构体中填入模型信息。

参数:

  • model_data:模型文件的起始地址

  • model_size:模型文件大小

  • model:返回的结构体里不仅包含了模型文件的handle,还有模型输入输出的节点信息

int HB_BPU_releaseModel(BPU_MODEL_S *model);

释放已经加载的模型。这个函数通常在模型不再被使用后调用,用于资源回收和释放。

10.1.2.4. 模型信息获取的接口

const char* BPU_getVersion(BPUHandle handle):

获取 BPU 模型的版本号。

int BPU_getModelNameList(BPUHandle handle, const char*** name_list, int *name_list_cnt):

获取模型文件中包含的所有模型 name。通常用户应该了解模型文件中的都是哪些模型,但是可能对具体 name 记不清楚,因此可以调用这个接口查看。后续调用其他 model 相关接口时,传入的 name,要求都是这个 name_list 中的某一个。

int BPU_getModelOutputInfo(BPUHandle handle, const char* model_name, BPUModelInfo *info):

获取 model 的 output 信息。包括 output 个数,output-shape, output-data-type。这个函数的主要作用在于,需要用户自己为 output-data 申请 buffer。因此,需要根据 output-shape,output-type 来确定 output-data buffer 需要的内存空间大小(详情参见 example 部分)。

const char *HB_BPU_getErrorName(int error_code)

用于返回 BPU 执行过程中的错误码信息,输入参数为所有BPU接口的返回值。

10.1.2.5. 模型执行接口

int BPU_runModelFromPyramid(BPUHandle handle, const char* model_name,
                            BPUPyramidBuffer input,
                            int pyr_level,
                            BPU_Buffer_Handle output[],
                            int nOutput,
                            BPUModelHandle *model_handle,
                            BPU_Buffer_Handle *extra_input = nullptr,
                            int extra_input_size = 0,
                            int core_id = -1);

针对从 pyramid 读取到的图片执行 model。

参数:

handle

代表加载模型的 BPU handle。

model_name

将要被执行的模型的名称。

input

调用 BPU IO 接口中获取的 pyramid buffer。

pyr_level

指的是用哪一层来执行模型。例如,0 表示使用原图,4 表示用1/2图。

extra_input

多输入模型的额外输入。

extra_input_size

多输入尺寸的额外输入。

core_id

运行模型的 core ID。

关于 pyramid 详情,参见 Pyramid 接口。

output

用于获取输出数据的 BPU_Buffer 数组指针,需要在调用函数之前首先创建出 BPU_Buffer。函数内部不会对 output 申请内存,output 内存由用户自己维护。

nOutput

BPU_Buffer 数组中的元素数。必须等于模型输出数。

model_handle

代表该运行环境的模型执行 handle。

返回值:

  • 返回值为0,则表示执行成功。

  • 返回值非0,则表示执行失败。可以调用 BPU_getLastError 获取错误信息。

这是个异步执行接口,会将执行任务添加至任务队列。该任务将由后台 engine 执行。所以当该接口返回,并不意味着模型执行已经完成。当返回时,设置 BPUModelHandle 变量,且当调用 BPU_getModelOutput 函数时,可以输入 BPUModelHandle 变量,等待模型执行完成,获取执行结果。

int BPU_getModelOutput(BPUHandle handle, BPUModelHandle model_handle);

获取模型执行结果。实际上结果会被写入到 BPU_runModelFromPyramid 提供的 output buffer 中。这个函数的意义在于等结果。也就是调用这个函数会 hang 住当前线程,直到模型执行完成,生成结果。在接口返回0后,output buffer 可以被访问。

int BPU_runModelCropPyramid(BPUHandle handle, const char *model_name,
                            BPUPyramidBuffer input,
                            int pyr_level,
                            int start_x,
                            int start_y,
                            BPU_Buffer_Handle output[],
                            int nOutput,
                            BPUModelHandle *model_handle,
                            BPU_Buffer_Handle *extra_input = nullptr,
                            int extra_input_size = 0,
                            int core_id = -1);

用于执行 ROI 检测。(start_x, start_y) 是 ROI 的左上顶点。

int BPU_releaseModelHandle(BPUHandle handle, BPUModelHandle model_handle);

释放模型 handle 信息。如果当前的 handle 正在等结果,则终止等待,释放所有相关资源。如果模型已经完成,则释放所有相关资源。

Note

release之后的 modelHandle 不能再被使用。

int BPU_runModelFromResizer(BPUHandle handle, const char* model_name,
                            BPUPyramidBuffer input,
                            BPUBBox *bbox,
                            int nBox,
                            int *resizable_cnt,
                            BPU_Buffer_Handle output[],
                            int nOutput,
                            BPUModelHandle *model_handle,
                            int core_id = -1);

该接口的使用方式跟 BPU_runModelFromPyramid 基本一样。这个函数的功能是对检测框的内容做进一步的识别。例如,在检测阶段识别了行人,可以在这个阶段再对行人的朝向进行识别。

参数:

handle

和 BPU_runModelFromPyramid 相同。

model_name

想要运行的模型名称。例如,行人朝向模型名称。

input

和 BPU_runModelFromPyramid 相同。

bbox

从检测阶段获取的检测框。

nBox

检测框数量。

resizable_cnt

可用于运行模型的框的数量。

由于硬件限制,并不是所有的检测框都能由 BPU 处理,所以,该参数用于告诉用户已经处理的框的数量。

当该接口返回,会设置 bbox 为 resizable。如果检测框可以处理,bbox->resizable 设置为 true,否则设置为 false。

output

和 the BPU_runModelFromPyramid 相同。

nOutput

和 BPU_runModelFromPyramid 相同。

model_handle

和 BPU_runModelFromPyramid 相同。

int HB_BPU_runModel(const BPU_MODEL_S *model,
                    const BPU_TENSOR_S input_data[],
                    const int input_num,
                    const BPU_TENSOR_S output_data[],
                    const int output_num,
                    const BPU_RUN_CTRL_S *run_ctrl,
                    bool is_sync,
                    BPU_MODEL_HANDLE *task_handle);

上述的执行接口均为异步执行,而该接口可支持同步或异步两种运行模式。当处于同步方式时,调用该接口会阻塞当前线程,直到模型运行完成;当处于异步方式时,同BPU_runModelFromPyramid一样调用该接口在将任务加入队列后会立即返回,之后可以通过task_handle等待运行结束。

参数:

model

包括模型的handle及输入输出信息。

input_data

模型输入数据,包括了输入的类型,shape以及内存地址等信息。

input_num

输入个数。

output_data

模型输出数据,包括了输出的 shape 以及内存地址等信息。

output_num

输出个数。

run_ctrl

模型运行的控制信息,包括运行的 core id。

is_sync

是否支持同步模式。

task_handle

当前运行的任务handle,当处于同步方式时,可置为 nullptr,当处于异步方式时,可通过 task_handle 等待模型结束。

int HB_BPU_waitModelDone(BPU_MODEL_HANDLE *task_handle);

获取模型执行结果。和BPU_getModelOutput相同,实际上结果会被写入到 HB_BPU_runModel 的 output_data 中。这个函数的意义在于等结果。也就是调用这个函数会 hang 住当前线程,直到模型执行完成,生成结果。在接口返回0后,output_data 中的内存地址可以被访问。

int HB_BPU_releaseTask(BPU_MODEL_HANDLE *task_handle);

释放任务的 handle 信息。如果当前的任务正在等结果,则终止等待,释放所有相关资源。如果任务已经完成,则释放所有相关资源。

10.1.2.6. 模型结果解析接口

该函数用于解析模型输出op为RPP时的检测结果,会将检测结果保存在结构体 BPURppBBox 中。

int BPU_parseRPPResult(BPUHandle handle, const char *model_name, BPU_Buffer_Handle output[], int output_index, BPURppBBox *rpp_bbox);

BPU_convertLayout可用于对数据的内存布局进行多种方法的转换,枚举 BPULayoutType 列出了可支持的转换方法。

int BPU_convertLayout(BPUHandle handle, void *to_data, const void *from_data,
                      const char *model_name, BPULayoutType layout_type,
                      uint32_t layer_index, uint32_t n_index,
                      uint32_t h_index, uint32_t w_index, uint32_t c_index)

同BPU_convertLayout一样,HB_BPU_convertLayout也可用于对数据的内存布局进行多种方法的转换,枚举 BPU_CONVERT_LAYOUT_METHOD_E 列出了可支持的转换方法。

int HB_BPU_convertLayout(const BPU_MODEL_S *model, void *to_data,
                         const void *from_data,
                         BPU_CONVERT_LAYOUT_METHOD_E convert_method,
                         uint32_t output_index, uint32_t n_index,
                         uint32_t h_index, uint32_t w_index, uint32_t c_index)

10.1.2.7. BPU内存接口

Bernoulli架构中BPU和CPU共享同一块memory空间,这里单独提供针对BPU内存的接口是因为bpu需要使用物理空间连续的内存,因此需要用专门的函数申请和释放。

int HB_SYS_bpuMemAlloc(const char *name, size_t alloc_mem_size, bool cachable, BPU_MEMORY_S *mem)

该函数返回申请到的memory地址,并且内存可被设置是否cacheable,BPU_MEMORY_S 结构体中包括物理地址,虚拟地址以及内存大小。

int HB_SYS_flushMemCache(const BPU_MEMORY_S *mem, int flag)

对于申请为cacheable的内存,在对memory进行读写操作时需要调用此接口,避免memory中的数据未及时更新。

int HB_SYS_isMemCachable(const BPU_MEMORY_S *mem)

查询内存是否是cacheable的。

int HB_SYS_bpuMemFree(BPU_MEMORY_S *mem);

释放BPU内存。

10.1.2.8. BPU缩放接口

int HB_BPU_resize(const BPU_TENSOR_S *src, BPU_TENSOR_S *dest, const BPU_RESIZE_CTRL_S *ctrl_param);

对输入的数据做缩放,转成结构体dest中指定的大小,并存储到dest中,缩放结果是填充后的。

int HB_BPU_cropAndResize(const BPU_TENSOR_S *src, const BPU_ROI_S *input_roi, BPU_TENSOR_S *dest, const BPU_RESIZE_CTRL_S *ctrl_param);

对输入的数据指定roi做缩放,转成结构体dest中指定的大小,并存储到dest中,缩放结果是填充后的。

int HB_BPU_getResizeResultWithoutPadding(const BPU_MEMORY_S *src, BPU_MEMORY_S *dest, const BPU_DATA_SHAPE_S *shape);

得到去padding的缩放结果。

int HB_BPU_getImageAlignedShape(const BPU_DATA_SHAPE_S *shape, int *aligned_size)

由有效的输入shape得到填充后的对齐大小。

10.1.2.9. BPU_Buffer 结构

这个结构表示了BPU相关操作使用的内存 buffer。实际上是一个 handle。提供两个接口供用户获取实际可以访问的内存地址。

void* BPU_getRawBufferPtr(BPU_Buffer_Handle buff)

返回用户可以访问的内存地址。用户可以写入或者读取内存中的内容。

int BPU_getRawBufferSize(BPU_Buffer_Handle buff)

返回 buffer 的 size。告诉用户具体 buffer 大小,防止出现非法内存访问。

BPU_Buffer_Handle BPU_createBPUBuffer(void *buff, int size)

对用户传入的 buffer,创建一个同样大小的 BPU buffer。

int BPU_freeBPUBuffer(BPU_Buffer_Handle buff)

释放申请的 buffer。

10.1.2.10. Pyramid 接口

BPU 提供了硬件实现图像金字塔的功能。可以对输入的一张图像做出不同 scale 的多张图像。这个功能主要是在后验证模型上,通过使用不同 scale 的图像,能够提升不同大小的检测框的识别精度。

在 X2/J2 芯片架构中,camera 采集的图像都要先通过 pyramid 处理之后,用户才能够拿到。因此,这里没有提供camera接口,只提供了pyramid接口。

typedef void* BPUPyramidHandle

int BPU_createPyramid(const char* vio_config_file_name, const char *camera_config-file_name, int cam_cfg_index, int port, BPUPyramidHandle *handle):

在使用 pyramid 模块之前,需要先创建对应的 handle。

参数:

vio_config_file_name

指 IO 相关的配置文件路径。

camera_config_file_name

指 camera 的配置文件路径。

cam_cfg_index

指 camera 配置文件中的config编号。

port

指对应编号config中的pord id。

handle

代表 pyramid 模块的 handle。

int BPU_getPyramidResult(BPUPyramidHandle handle, BPUPyramidBuffer *buffer):

获取金字塔的结果。如果还没有图像进来,则会 hang 住当前线程,等待金字塔做完。

int BPU_releasePyramidResult(BPUPyramidHandle handle, BPUPyramidBuffer buffer):

释放金字塔返回的结果。由于 pyramid 内部申请了 result 的内存空间,如果不释放,会造成内存泄漏。而且,pyramid 内部空间有限制,持续不释放会导致内存超限,无法再返回结果。

int BPU_releasePyramid(BPUPyramidHandle handle):

释放金字塔模块占用的资源。释放之后不能再使用该 handle。

获取 pyramid 信息接口

由于 BPUPyramidBuffer 只是一个表示 pyramid 对象的 handle,并没有包含 camera frame 信息,用户也不能直接得到 frame 的数据。因此,这里提供了一些接口用于获得 frame 信息以及金字塔每一层的 buffer。

uint64_t BPU_getPyramidTimestamp(BPUPyramidBuffer buffer);

获取产生金字塔的图像 frame 对应的 timestamp。

int BPU_getPyramidFrameID(BPUPyramidBuffer buffer);

获取产生金字塔的原始图像的 frame ID。

为了支持获取金字塔每一层的 buffer,提供以下回调方式:

void BPU_processPyramidResult(BPUPyramidBuffer pyr_buffer, int pyr_level, BPU_pyramidCallBack cb, void *cb_data_ptr);

pyr_level 表示想要获取的金字塔的层 ID,函数内部会调用回调函数,把对应的那一层 buffer 传递给回调函数。

金字塔生成层的方式:根据 vio 配置文件中 pymid_ctrl_configpymid_ds_config,可以控制金字塔生成的层数。其中,0层表示原始图像,4、8、12等4的倍数层分别是原始图像的1/2、1/4和1/8层。配置文件中的1、2、3、5、6、7等层是根据ROI做对应factor的scale。一般都是使用4的倍数层。

10.1.2.11. FakeImage接口

在 X2/J2 开发板中,camera 的输入一版为1080p或720p。但是,通常训练的深度学习模型的输入图片的清晰度都不是这么大。例如,分类模型是224x224,检测模型是416x416。为支持输入任意大小的图像,我们提供了 FakeImage 接口,用户可以使用该接口输入任意大小的图像在 BPU 上运行模型。

typedef void* BPUFakeImageHandle

定义一个 FakeImage 的 handle。每个 handle 可以用于表示一种大小的图片。

int BPU_createFakeImageHandle(int height, int width, BPUFakeImageHandle *handle);

创建 FakeImage 的 handle,其中 height 和 width 表示图片的大小。

BPUFakeImage *BPU_getFakeImage(BPUFakeImageHandle handle, uint8_t *yuv_nv12_ptr, int img_len);

用户需要自己传入一个 yuv nv12 格式的图像。然后,该函数会返回对应图像的 BPUFakeImage 结构,fake image 可以用来执行模型。img_len 表示 yuv_nv12_ptr 指向的图像 buffer 大小,要求跟创建 handle 使用的 height 和 width 相匹配(img_len == height * width * 3 / 2)。

int BPU_runModelFromImage(BPUHandle handle, const char *model_name, BPUFakeImage *input, BPU_Buffer_Handle output[], int nOutput, BPUModelHandle *model_handle, BPU_Buffer_Handle *extra_input = nullptr, int extra_input_size = 0, int core_id = -1);

输出 input 改成了 BPUFakeImage 指针之外,使用方式跟其他 runModel 函数一致。

int BPU_releaseFakeImage(BPUFakeImageHandle handle, BPUFakeImage *image_ptr);

释放 fake image 对象。要求使用完之后执行释放函数,否则会造成内存泄漏。

int BPU_releaseFakeImageHandle(BPUFakeImageHandle handle);

释放 FakeImage 的 handle。FakeImage 的 handle 可以针对不同大小的图像,创建多个 handle。

10.1.2.12. Feedback 接口

上文所述 FakeImage 接口不支持对 image 图像做金字塔。因此,不能跑需要做金字塔的模型。Feedback 接口利用系统硬件的金字塔功能,实现把用户输入的图像做金字塔,然后就可以对金字塔的结果来执行模型。

typedef void *BPUFeedbackHandle;

int BPU_createFeedback(const char *fb_config_file, BPUFeedbackHandle *handle);

创建 feedback 的 handle。其中,fb_config_file 是 feedback 的配置文件,主要是为了配置输入图像的大小和对应的 pyramid 的大小。类似于 vio 的 config 文件。

int BPU_getFeedbackResult(BPUFeedbackHandle handle, void *data_ptr, int data_len, BPUPyramidBuffer *pyr_buffer);

用户传入需要测试的图像 buffer 指针和图像大小,得到对应的金字塔结果 buffer。其中,图像要求是 yuv nv12 格式,data_len 要求和 config 文件中的图像大小匹配。目前仅支持1080p和720p的图像。

int BPU_releaseFeedbackResult(BPUFeedbackHandle handle, BPUPyramidBuffer pyr_buffer);

释放 pyramid buffer。pyramid buffer 占用了内部的内存资源,因此用完之后一定要释放,否则会造成内存泄漏。

int BPU_releaseFeedbackHandle(BPUFeedbackHandle handle);

释放 feedback handle。

10.1.2.13. BPU Group 接口

BPU Group 让用户能将一些模型放入其中,并通过该组进行管理。

int BPU_createGroup(BPUHandle handle);

创建 BPU Group 对象并返回 Group ID(大于0)。Group ID 0是默认组,因此无法创建 group ID 为0的组。

int BPU_setModelGroup(BPUHandle handle, const char* model_name, int group_id);

将模型设置到 group 中,默认所有的模型属于 group 0(ID为0 的group)。若想要将模型换至另一个 group,用另一个 group ID 调用该接口。若想要从 group 中移除模型,用group ID 0调用该接口。

int BPU_setGroupProportion(BPUHandle handle, int group_id, int proportion);

用 group ID 设置该组的 BPU 计算时间片的比例。比例为整数,真正比例 RP 是整个 BPU 计算时间的比例,因此将按 RP = proportion / 100计算。

如果该组有超过一个模型,该组所有的模型共享 group 比例。即,假定设置比例为50,group 中包括 model1、model2 和model3,则计算时间为 group 中所有模型的计算时间之和。

当把一个模型设置到一个group中,并对group设置了计算比例,该模型会按照该group的比例运行。如果该组的计算时间耗完,那么这个模型将会排列等候,直到当前组获得更多的计算时间。

10.1.2.14. BPUCNNBuffer接口

这套接口允许用户在应用层对输入进行自定义配置,其整体流程与Pyramid接口相同,唯一的区别是输入由用户构造,数据模拟金字塔结构。

struct BPUCNNBuffer;
BPUCNNBuffer *BPU_createBPUCNNBuffer(int width, int height,
                  int channel, size_t lv_cnt);

通过此接口创建BPUCNNBuffer结构。

int BPU_getHBMhandleFromBPUhandle(BPUHandle handle, uint64_t * hbm_handle);

通过此接口获取某层金字塔的地址,后续可对此地址做赋值等操作。

int BPU_runModelFromCNNBuffer(BPUHandle handle, const char* model_name,
                BPUCNNBuffer *input_y,
                BPUCNNBuffer *input_uv,
                int pyr_level,
                BPU_Buffer_Handle output[],
                int nOutput,
                BPUModelHandle *model_handle,
                BPU_Buffer_Handle *extra_input = nullptr,
                int extra_input_size = 0,
                int core_id = -1);

通过此方法run pyramid,其余输入参数获取可参考Pyramid接口流程。

int BPU_runModelFromResizerBuffer(BPUHandle handle, const char* model_name,
                BPUCNNBuffer *input_y,
                BPUCNNBuffer *input_uv,
                BPUBBox *bbox,
                int nBox,
                int *resizable_cnt,
                BPU_Buffer_Handle output[],
                int nOutput,
                BPUModelHandle *model_handle,
                int core_id = -1);

通过此方法run resizer 其余输入参数获取可参考Resizer流程。

int BPU_freeBPUCNNBuffer(BPUCNNBuffer *buff);

对BPUCNNBuffer释放。

10.1.3. 示例

以下基于 BPU API,做了一个代码使用示例,实现的功能是从 camera 采集图像,对图像执行检测模型,对输出进行解析以获取检测框,并在客户端做结果的展示。

具体示例代码,参见附件包中的程序。

10.1.3.1. 加载模型

const char *bpu_model = args.model_file.c_str();
BPUHandle bpu_handle;
int ret = BPU_loadModel(bpu_model, &bpu_handle);
if (ret != 0) {
  std::cout << "here load bpu model failed: " << BPU_getLastError(bpu_handle) << std::endl;
  return 1;
}
std::cout << "here load bpu model OK" << std::endl;

// get bpu version
const char *version = BPU_getVersion(bpu_handle);
if (version == nullptr) {
  std::cout << "here get bpu version failed: " << BPU_getLastError(bpu_handle) << std::endl;
  return 1;
}
std::cout << "here get bpu version: " << version << std::endl;

调用 load 函数加载模型,指定模型文件 (.hbm) 的路径,然后调用 BPU_getVersion 接口获取版本信息。

10.1.3.2. 获取模型信息

调用 getModelNameList 函数,获取模型文件中包含的所有模型的 name。

// get model names
const char **name_list;
int name_cnt;
ret = BPU_getModelNameList(bpu_handle, &name_list, &name_cnt);
if (ret != 0) {
  std::cout << "here get name list failed: " << BPU_getLastError(bpu_handle) << std::endl;
  return 1;
}

// print all name list
std::cout << "here get all name list: " << name_cnt << " list below: " << std::endl;
for (int i = 0; i < name_cnt; ++i) {
  std::cout << name_list[i] << std::endl;
}

然后可以调用 BPU_getModelInputInfoBPU_getModelOutputInfo 接口获取模型输入和输出信息。如下所示,获取信息后,输出模型的输入和输出 shape。

int ret = BPU_getModelInputInfo(bpu_handle, model_name, &output_info);
std::cout << "model: " << model_name << " input info: " << std::endl;
for (int i = 0; i < output_info.num; ++i) {
    std::cout << "(";
    for (int j = output_info.ndim_array[i]; j < output_info.ndim_array[i+1]; ++j) {
    std::cout << output_info.valid_shape_array[j] << ",";
    }
    std::cout << ")" << std::endl;
}

ret = BPU_getModelOutputInfo(bpu_handle, model_name, &output_info);
if (ret != 0) {
    std::cout << "get model: " << model_name << " output info failed: " << BPU_getLastError(bpu_handle) << std::endl;
    return 1;
}

std::cout << "model: " << model_name << " has output: " << output_info.num << std::endl;
for (int i = 0; i < output_info.num; ++i) {
    std::cout << "name: " << output_info.name_list[i] << ", shape: ";
    std::cout << "(";
    for (int j = output_info.ndim_array[i]; j < output_info.ndim_array[i+1]; ++j) {
    std::cout << output_info.aligned_shape_array[j] << ",";
    }
    std::cout << ")" << std::endl;
    int out_type_size = sizeof(int8_t);
    if (output_info.dtype_array[i] == BPU_DTYPE_FLOAT32) {
    out_type_size = sizeof(float);
    }
    std::cout << "output size: " << out_type_size << std::endl;
}
return output_info.num;

10.1.3.3. 创建 Pyramid

为了从 camera 采集图像,需要首先创建 pyramid 的 handle,需要两个参数文件:hb_vio.jsonhb_camera.json

BPUPyramidHandle pyr_handle;
// use pyramid
const char *vio_config = "./config/hb_vio.json";
const char *camera_config = "./config/hb_camera.json";
ret = BPU_createPyramid(vio_config, camera_config, 0, 0, &pyr_handle);
if (ret != 0) {
  std::cout << "create pyramid failed" << std::endl;
  return 1;
}

10.1.3.4. 创建打包和发送模块

图像检测的结果需要通过网路发送给 client 做展示。因此,需要创建 output-sender 对象发送结果至客户端:

OutputSender msg_sender;
ret = msg_sender.init("tcp://*:5560"); // set pubish port is 5560
if (ret != 0) {
  std::cout << "create msg sender failed" << std::endl;
  return -1;
}

10.1.3.5. 采集图像并执行检测模块

BPUPyramidBuffer pyr_buffer;
  ret = BPU_getPyramidResult(pyr_handle, &pyr_buffer);
  if (ret != 0) {
    std::cout << "get pyramid result failed" << std::endl;
    return 1;
  }

  frame.timestamp = BPU_getPyramidTimestamp(pyr_buffer);
  frame.frame_id = BPU_getPyramidFrameID(pyr_buffer);

  alloc_output_buffer(out_buf, out_num);
  BPUModelHandle model_handle;
  // run model
  ret = BPU_runModelFromPyramid(bpu_handle, model_name, pyr_buffer, 0,
                                out_buf.data(), out_buf.size(),
                                &model_handle);
  if (ret != 0) {
    std::cout << "run model from pyramid failed" << std::endl;
    return 1;
  }

由于模型会在后台运行一段时间,因此,可以同时从pym buffer里面获取要展示的图像。

执行模型的工作是由后端引擎做的,这里是异步接口。因此,调用 BPU_processPyramidResult 函数并不影响模型的正常执行。

BPU_processPyramidResult(pyr_buffer, 0, dump_pyramid_image, pyr_img_ptr);

  // wait for model run done, and get output
  ret = BPU_getModelOutput(bpu_handle, model_handle);
  if (ret != 0) {
    std::cout << "here get model output failed: "
              << BPU_getLastError(bpu_handle);
    return 1;
  }

10.1.3.6. 解析结果

解析模型输出结果,得到检测框:

if (args.is_ssd) {
    uint32_t num_layer = out_num/2;
    SSDAux(bpu_handle, output_info, out_buf.data(), num_layer,
            anchors_table, result_vec, 0.3, args.is_tf_model, false);
    } else if (args.is_yolo) {
    YoloAux(bpu_handle, output_info, model_name, out_buf.data(), 3, result_vec, 20, 0.3, 0.45,
            args.is_tf_model, false);

检测模型的输出格式需要经过专门解析,ssd_aux 和 yolo_aux 用于解 SSD 和 YOLO 模型输出的结果。

10.1.3.7. 打包发送

对图像 frame 和检测结果进行序列化打包,这样才能发送给 client:

// serialize to pb
  char *pb_buffer = nullptr;
  int pb_buf_len;
  ret = serialize(&frame, perception_data.data(), perception_data.size(), &pb_buffer, &pb_buf_len);
  if (ret != 0) {
    std::cout << "serialize to pb failed" << std::endl;
  }

  uint8_t* yuv_ptr = reinterpret_cast<uint8_t *>(pyr_img_ptr);

  // send msg and wait send done
  output_mq_sent = false;
  ret = msg_sender.send_msg(pb_buffer, pb_buf_len, yuv_ptr, img_len, output_send_mq_cb);
  if (ret != 0) {
    free(pb_buffer);
    pb_buffer = nullptr;
    std::cout << "send msg failed" << std::endl;
  }

  // wait for msg send done.
  if (!output_mq_sent) {
    wait_output_sent();
  }

打包发送完成之后,需要释放 frame。

// release
BPU_releasePyramidResult(pyr_handle, pyr_buffer);

10.1.3.8. 收尾工作

在程序退出之前,必须释放创建的各种 handle。

if (pyr_img_ptr != nullptr) {
  free(pyr_img_ptr);
}

BPU_releasePyramid(pyr_handle);

BPU_release(bpu_handle);

检测效果:

../_images/Conclude_the_Work_2.png

BPU API 参见《MU-2020-1-C-X2J2平台系统软件接口手册》。

10.2. HBDK 运行时 API

10.2.1. 运行时概述

HBDK 运行时的目标是为用户提供低层次访问存储在 HBM 文件信息的接口,这些 HBM 文件是由 HBDK 工具链产生的。 HBDK 运行时为用户提供了以下功能:

  • 加载 HBM 文件,其中可以包含多个模型

  • 从加载的 HBM 文件中加载模型

  • 为指定的模型创建运行实例

  • 为指定的运行实例创建 Funccall

  • 启动开始执行 Funccall

  • 一旦指定模型的所有 Funccall 全部执行完,可以将运行输出结果从 BPU DRAM 的输出区拷贝到 CPU 的 DRAM

  • 销毁指定模型的运行实例

  • 卸载 HBM

下图展示了 HBDK 运行时的使用示例。

hbrt_diagram

本小节的剩余部分会列出 HBDK 每个运行时函数接口的原型以及用法。

10.2.2. 加载/卸载/验证HBM

函数原型

hbrt_error_t hbrtLoadHBMFromAddr(hbrt_hbm_handle_t *hbm_handle, void *hbm_address, size_t hbm_byte_size)

功能

从指定的 BPU 地址装载 HBM 文件

参数

[输出] hbm_handle: 要装载的 HBM 文件的句柄,可用于其它 API 获得模型信息的参数。

[输入] hbm_address: 指向 HBM 文件的地址。

[输入] hbm_byte_size: HBM 文件的大小(单位 Byte)。

说明

此函数在装载的时候,会检查 HBM 文件和 HBDK 运行时版本的兼容性。


函数原型

hbrt_error_t hbrtLoadHBMFromFile (hbrt_hbm_handle_t *hbm_handle, const char *hbm_path)

功能

装载指定路径上的 HBM 文件

参数

[输出] hbm_handle: 要装载的 HBM 文件的句柄,可用于其它 API 获得模型信息的参数。

[输入] hbm_path: 要装载的 HBM 文件的路径。

说明


函数原型

hbrt_error_t hbrtOffloadHBM (const hbrt_hbm_handle_t *hbm_handle)

功能

卸载 hbm_handle 指定的 HBM 文件

参数

[输入] hbm_handle: 要卸载的 HBM 文件的句柄.

说明

用户必须显式销毁和此 HBM 文件中模型绑定的所有所有运行实例,否则将返回一个 hbrtErrorRiIsInUse 状态码。一旦 HBM 被卸载,其他 API 将不能访问此 HBM 文件中模型的任何信息。


函数原型

hbrt_error_t hbrtVerifyHBM(const void *hbm_address)

功能

验证 HBM 文件的 CRC32 校验码

参数

[输入] hbm_address: 指向一个 HBM 二进制文件的地址.

说明

在调用 hbrtLoadFromAddr 之前必须验证 hbm_address, 例如:
  1. hbm_address = OpenFile(HBM);

  2. hbrtVerifyHBM(hbm_address);

  3. hbrtLoadFromAddr(hbm_address);

在调用 hbrtLoadHBMFromAddr 之后会导致验证失败,因为 hbrtLoadHBMFromAddr 会将二进制文件中的一 些指针重定位。


10.2.3. 提取模型信息

函数原型

hbrt_error_t hbrtGetModelNumberInHBM(uint32_t *model_number, hbrt_hbm_handle_t hbm_handle)

功能

提取HBM内部模型数量。

参数

[输出] model_number: 返回的模型数量。

[输入] hbm_handle: HBM句柄。

说明


函数原型

hbrt_error_t hbrtGetModelNamesInHBM(const char ***model_names, hbrt_hbm_handle_t hbm_handle)

功能

通过HBM句柄读取内部所有模型的名称。

参数

[输出] model_names: 返回字符串型指针组包含所有的模型名称。

[输入] hbm_handle: HBM句柄。

说明


函数原型

hbrt_error_t hbrtGetModelHandle(hbrt_model_handle_t *model_handle, hbrt_hbm_handle_t hbm_handle, const char *model_name)

功能

通过模型名称查询模型句柄。

参数

[输出] model_handle: 返回的模型句柄。

[输入] hbm_handle: HBM句柄。

[输入] model_name: 模型名称。

说明


函数原型

hbrt_error_t hbrtGetModelMarch(MARCH *march, hbrt_model_handle_t model_handle)

功能

返回模型MARCH。

参数

[输出] march: 该模型的MARCH。

[输入] model_handle: 模型句柄。

说明


函数原型

hbrt_error_t hbrtGetModelCoreNumber(uint8_t *core_num, hbrt_model_handle_t model_handle)

功能

返回模型执行需要的BPU核心数量。

参数

[输出] core_num: 模型执行需要的BPU核心数量。

[输入] model_handle: 模型句柄。

说明

模型执行需要的BPU核心数量在编译时被指定。双核模型必须占用两个BPU来完成计算。


函数原型

hbrt_error_t hbrtGetModelPeNumber(uint8_t *pe_num, hbrt_model_handle_t model_handle)

功能

返回模型计算阵列数量。

参数

[输出] pe_num: 计算阵列数量。

[输入] model_handle: 模型句柄。

说明

模型执行需要的计算阵列数量在编译时被指定。双阵列模型必须占用两个计算阵列来完成计算。


函数原型

hbrt_error_t hbrtIsOneSegmentModel(bool *is_one_segment_model, hbrt_model_handle_t model_handle)

功能

检查模型是否只包含单个网络片段。

参数

[输出] is_one_segment_model: 返回True,如果模型只包含单个网路片段。

[输入] model_handle: 模型句柄。

说明


10.2.4. 提取特征信息

函数原型

hbrt_error_t hbrtGetInputFeatureHandles(hbrt_feature_handle_t **feature_handle,hbrt_model_handle_t model_handle);

功能

获得模型输入特征句柄

参数

[输出] feature_handle: 输入特征句柄

[输入] model_handle: 模型句柄

说明


函数原型

hbrt_error_t hbrtGetInputFeatureNumber(uint32_t *input_number,hbrt_model_handle_t model_handle);

功能

获得模型输入特征数目

参数

[输出] input_number: 输入特征数目指针

[输入] model_handle: 模型句柄

说明


函数原型

hbrt_error_t hbrtGetOutputFeatureHandles(hbrt_feature_handle_t **feature_handle,hbrt_model_handle_t model_handle);

功能

获得模型输出特征句柄

参数

[输出] feature_handle: 输出特征句柄

[输入] model_handle: 模型句柄

说明


函数原型

hbrt_error_t hbrtGetOutputFeatureNumber(uint32_t *output_number,hbrt_model_handle_t model_handle);

功能

获得模型输出特征数目

参数

[输出] output_number:模型输出数目指针

[输入] model_handle: 模型句柄

说明


函数原型

hbrt_error_t hbrtGetOutputFeatureTotalSize(uint32_t *size,hbrt_model_handle_t model_handle);

功能

获得指定输出特征大小

参数

[输出]size:输出特征大小

[输入] model_handle: 模型句柄

说明


函数原型

hbrt_error_t hbrtGetFeatureName(const char **name,hbrt_feature_handle_t feature_handle);

功能

获得指定特征句柄的特征名称

参数

[输出]name:特征名称

[输入]feature_handle:模型句柄

说明


函数原型

hbrt_error_t hbrtGetFeatureAlignedDimension(hbrt_dimension_t *dim,hbrt_feature_handle_t feature_handle);

功能

获得指定特征的对齐维度

参数

[输出]dim:特征各个维度对齐尺寸

[输入]feature_handle:模型句柄

说明

对齐BPU位宽,某些维度的特征可能加pad。此功能占用的字节大小应根据对齐尺寸计算获得。


函数原型

hbrt_error_t hbrtGetFeatureValidDimension(hbrt_dimension_t *dim,hbrt_feature_handle_t feature_handle);

功能

获得指定特征的有效维度

参数

[输出]dim:特征各个维度真实尺寸

[输入]feature_handle:特征句柄

说明


函数原型

hbrt_error_t hbrtGetFeatureAlignedTotalByteSize(uint32_t *size,hbrt_feature_handle_t feature_handle);

功能

获得指定特征的对齐后总大小

参数

[输出]size:对齐后特征的所占内存的字节数

[输入]feature_handle:特征句柄

说明

此函数为指定特征返回(aligned dim *element type)


函数原型

hbrt_error_t hbrtGetFeatureValidTotalByteSize(uint32_t *size,hbrt_feature_handle_t feature_handle);

功能

获得指定特征的有效数据总大小

参数

[输出]size:特征有效数据所占内存的字节数

[输入]feature_handle:特征句柄

说明

此函数为指定特征返回(aligned dim *element type)


函数原型

hbrt_error_t hbrtGetFeatureShiftValues(const uint8_t **shift, hbrt_feature_handle_t feature_handle);

功能

获得指定特征的各个通道移位值

参数

[输出]shift:特征各个通道移位值

[输入]feature_handle:特征句柄

说明


函数原型

hbrt_error_t GetFeatureShiftValueNumber(uint32_t *num,hbrt_feature_handle_t feature_handle);

功能

获得指定特征的移位值的个数

参数

[输出]num:移位值的个数

[输入]feature_handle:特征句柄

说明


函数原型

hbrt_error_t hbrtGetFeatureScaleValues(const float **scale, hbrt_feature_handle_t feature_handle)

功能

获得指定特征的各个缩放值。

参数

[输出]shift:特征的图的缩放值。

[输入]feature_handle:特征句柄。

说明


函数原型

hbrt_error_t hbrtGetFeatureScaleValueNumber(uint32_t *num, hbrt_feature_handle_t feature_handle)

功能

获得指定特征句柄的缩放值数量。

参数

[输出] num: 缩放值数量。

[输入] feature_handle: 特征句柄。

说明


函数原型

hbrt_error_t hbrtGetFeatureQuantiType(hbrt_feature_quanti_type_t *type, hbrt_feature_handle_t feature_handle)

功能

获得特征量化类型。

参数

[输出] type:特征量化类型。

[输入] feature_handle:特征句柄。

说明


函数原型

hbrt_error_t hbrtGetFeatureElementType(hbrt_element_type_t *element_type,hbrt_feature_handle_t feature_handle);

功能

获得指定特征的元素类型。

参数

[输出]element_type:特征的数据类型。

[输入]feature_handle:特征句柄

说明

1.检查可支持元素类型hbrt_element_type_t的定义

2.由于DetectionPostProcess和RCNNPostProcess有结构化输出,用户应使用对应结构解析输出,而非检查从这个API获取的元素类型。

更多细节请参见hbrt_type.h中对bernoulli_hw_detection_post_process_bbox_type_t,cpu_op_rcnn_post_process_bbox_float _type_t的定义。


函数原型

hbrt_error_t hbrtGetFeatureLayoutType(hbrt_layout_type_t *layout,hbrt_feature_handle_t feature_handle)

功能

获得指定特征的数据排布

参数

[输出] layout: 特征的数据排布

[输入]feature_handle:特征句柄

说明

检查所支持数据排布hbrt_layout_type_t的定义。


函数原型

hbrt_error_t hbrtFeatureIsBigEndian(bool *isBigEndian,hbrt_feature_handle_t feature_handle);

功能

判断指定特征是否是以大端存储

参数

[输出]isBigEndian:特征是否是以大端存储

[输入]feature_handle:特征句柄

说明


函数原型

hbrt_error_t hbrtGetInputFeatureSource(hbrt_input_source_t *input_source,hbrt_feature_handle_t feature_handle)

功能

获得指定特征的输入特征源

参数

[输出]input_source:特征的输入源

[输入]feature_handle:特征句柄

说明

无输入特征句柄的输入源将返回INPUT_FROM_DDR


函数原型

hbrt_error_t hbrtGetInputSourceName(const char **name,hbrt_input_source_t source);

功能

获得特征输入源字符串描述

参数

[输出]name:特征输入源字符串描述

[输入] source: 输入源的枚举值

说明


函数原型

hbrt_error_t hbrtGetInputPyramidStride(uint32_t *stride,hbrt_feature_handle_t feature_handle)

功能

获得指定特征句柄的金字塔跨越值

参数

[输出]stride:特征的金字塔跨越值

[输入]feature_handle:特征句柄

说明

如用户通过非金字塔特征句柄则此函数返回hbrtInvalidFeatureHandle。


函数原型

hbrt_error_t hbrtGetFeatureOperatorType(hbrt_output_operator_type_t *type,hbrt_feature_handle_t feature_handle)

功能

获得指定特征句柄的算子

参数

[输出]type:特征来源的算子类型

[输入]feature_handle:特征句柄

说明

1.对于如RCNNPostProcess和DetectionPostProcess类算子将以相应格式输出。更多细节详请参见hbrt_type.h中对 bernoulli_hw_detection_post_process_bbox_type_t, cpu_op_rcnn_post_process_bbox_float_type_t的定义。

2.对其它类型特征都会有包括OUTPUT_BY_UNKNOWN的输出算子。


10.2.5. 执行模型

函数原型

hbrt_error_t hbrtRiStart(void **p_funccall_buffer, uint32_t *generated_funccall_num, hbrt_model_handle_t model_handle, const hbrt_ri_input_info_t *input_infos, const hbrt_ri_config_t *ri_config, uint32_t ri_id, uint32_t interrupt_number

功能

为执行模型推理生成 BPU Funccall

参数

[输出] p_funccall_buffer: 生成的 Funccall 将会写到这个指针所指地址处

[输出] generated_funccall_number: 生成的 Funccall 数目

[输入] model_handle: 要运行模型的句柄

[输入] input_infos: 模型的输入信息

[输入] ri_config: 此运行实例的配置

[输入] ri_id: 此运行实例的 id

[输入] interrupt_number: 指定最后一个 Funccall 运行完后产生的中断号

说明

1.有效的运行实例 id 范围为 0 到 MAX_RI_NUMBER。 MAX_RI_NUMBER 是一个在头文件 hbdk_hbrt.h 中定义的宏,

2.有效的终端号为 0 到 4095,

3.返回的 Funccall buffer 将会被 HBDK 运行时管理,用户代码不应尝试释放此 buffer。


函数原型

hbrt_error_t hbrtRiBatchStart(void **p_funccall_buffer, uint32_t *generated_funccall_num, hbrt_model_handle_t model_handle, const hbrt_ri_input_info_t **model_input_infos, const uint32_t *model_input_batch_size,const hbrt_ri_config_t *ri_config, uint32_t ri_id, uint32_t interrupt_number)

功能

为一批输入数据执行模型推理生成 BPU Funccall

参数

[输出] p_funccall_buffer: 生成的 Funccall 将会写到这个指针所指地址处

[输出] generated_funccall_number: 生成的 Funccall 数目

[输入] model_handle: 要运行模型的句柄

[输入] model_input_infos: 指向一个批处理数据输入信息的辅助指针。第一维遍历模型输入数目,第二维遍历此输入的批处理大小

[输入] model_input_batch_size: 指向批处理大小数组的指针。所有模型输入的批大小应为1或等于相同的数量

[输入] ri_config: 此运行实例的配置

[输入] ri_id: 此运行实例的 id

[输入] interrupt_number: 指定最后一个 Funccall 运行完后产生的中断号

说明

对于多输入模型,可以通过将相应的输入批处理大小设置为1来广播某些输入。只有 cpu-operator-free 的模型可以用此 API 启动


函数原型

hbrt_error_t hbrtRiContinue(void **funccall_buffer, uint32_t *generated_funccall_num, uint32_t ri_id, uint32_t interrupt_number)

功能

在需要时,在 CPU 上执行一部分模型。同时为剩余的层生成 Funccall

参数

[输出] p_funccall_buffer: 生成的 Funccall 将会写到这个指针所指地址处

[输出] generated_funccall_number: 生成的 Funccall 数目

[输入] ri_id: 此运行实例的 id

[输入] interrupt_number: 指定最后一个 Funccall 运行完后产生的中断号

说明

此函数的时间消耗可能是从几微秒到数十毫秒不等。 我们建议建立一个 pipeline,以使此函数与 BPU Funccall 的执行并行。


函数原型

hbrt_error_t hbrtRiDestroy(uint32_t ri_id)

功能

释放正在运行的实例占用的资源

参数

[输入] ri_id: 此运行实例的 id

说明

在调用hbrtRiDestroy释放它之前,不能选择 ri_id 重新启动另一个正在运行的实例


函数原型

hbrt_error_t hbrtRiIsDone(bool *is_done, uint32_t ri_id)

功能

返回与运行实例绑定的模型推断是否已完成

参数

[输出] is_done: true 表示模型已完全执行

[输入] ri_id: 此运行实例的 id

说明


函数原型

hbrt_error_t hbrtRiNextSegmentInvolveCpu(bool *involve_cpu, uint32_t ri_id)

功能

返回是否下一次调用 hbrtRiContinue 涉及 CPU 层计算

参数

[输出] involve_cpu: ture 代表指定的运行实例下一次调用 hbrtRiContinue 涉及 CPU 计算

[输入] ri_id: 此运行实例的 id

说明

此功能用于用户代码的 pipeline 调度


函数原型

hbrt_error_t hbrtBilinearRoiResizeImage(void **funccall_buffer, uint32_t *generated_funccall_num, bpu_addr_t image_y_addr, bpu_addr_t image_uv_addr, uint32_t image_height, uint32_t image_width, uint32_t image_h_stride, bool uv_enable, hbrt_pad_mode_t pad_mode,const hbrt_roi_t *p_rois, uint32_t roi_num, uint32_t dest_w, uint32_t dest_h, hbrt_layout_type_t output_layout, bpu_addr_t output_bpu_addr, uint32_t ri_id, MARCH march, uint32_t interrupt_num)

功能

生成 Funccall 以通过双线性插值来调整NV12图像的ROI大小

参数

[输出] funccall_buffer: 为剪裁和缩放生成的 Funccall

[输出] generated_funccall_num: 生成的 Funccall 数目

[输入] image_y_addr: 图像 Y 通道的地址

[输入] image_uv_addr: 图像 UV 通道的地址

[输入] image_height: 图像高度

[输入] image_width: 图像宽度

[输入] image_h_stride: 图像一行的 byte 大小

[输入] uv_enable: 是否剪裁和缩放 uv 通道

[输入] pad_mode: 超出图像边界范围的 pad 模式

[输入] p_rois: 指向 ROI 的指针

[输入] roi_num: ROI 的数目

[输入] dest_w: 指定的 ROI 将会被缩放到此宽度

[输入] dest_h: 指定的 ROI 将会被缩放到此高度

[输入] output_layout: 输出的排布

[输入] output_bpu_addr: 输出地址

[输入] ri_id: 执行此生成 Funccall 的运行实例 id

[输入] march: 参看说明

[输入] interrupt_num: 此生成的 Funccall 执行结束时产生的中断号

说明

1.输入图片的格式应为 YUV420NV12,

2.输出图片的格式为 YUV444。


函数原型

hbrt_error_t hbrtRiGetModelHandle(hbrt_model_handle_t *model_handle, uint32_t ri_id)

功能

从正在运行的实例索引获取模型句柄

参数

[输出] model_handle: 与运行实例绑定的模型句柄

[输入] ri_id: 运行实例的索引 id

说明


函数原型

hbrt_error_t hbrtRiGetConfig(const hbrt_ri_config_t **ri_config, uint32_t ri_id)

功能

从正在运行的实例索引中获取配置

参数

[输出] ri_config: 所指定运行实例的配置

[输入] ri_id: 运行实例的索引 id

说明


函数原型

hbrt_error_t hbrtRiGetInputInfo(const hbrt_ri_input_info_t **input_info, uint32_t ri_id)

功能

从正在运行的实例索引获取输入信息

参数

[输出] input_info: 与所指定运行实例绑定的模型的输入信息

[输入] ri_id: 运行实例的索引 id

说明


10.2.6. 获取模型输出

函数原型

hbrt_error_t hbrtRiGetOutputStatus(uint64_t *status, uint32_t ri_id);

功能

获得输出的状态.

参数

[输出] status: 输出状态位图

[输入] ri_id: 运行实例的ID

说明

在整个RI完成之前,可能已经生成了输出功能。(例如,具有几个 输出的大型模型)调用此函数以检查那个输出可以使用了。 状态是位图(如果设置了第0比特,则输出0准备就绪, 如果设置了第1比特,则输出1准备就绪,等等)


函数原型

hbrt_error_t hbrtRiGetFeatureBpuAddress(bpu_addr_t *addr, uint32_t ri_id, hbrt_feature_handle_t fh);

功能

获取指定运行实例的特征数据的BPU地址

参数

[输出] addr: 特征数据的BPU地址

[输入] ri_id: 运行实例的ID

[输入] fh: 特征数据的句柄

说明


函数原型

hbrt_error_t hbriGetFeatureData(void **data, uint32_t ri_id, hbrt_feature_handle_t fh, DATA_WORK work);

功能

获取指定运行实例的特征数据

参数

[输出] data: 特征数据

[输入] ri_id: 运行实例的ID

[输入] fh: 特征数据的句柄

[输入] work: 处理数据的方式,查看 ::DATA_WORK.

说明


函数原型

hbrt_error_t hbrtRiGetOutputData(void **data, uint32_t ri_id, uint32_t output_index, DATA_WORK work);

功能

获取指定运行实例输出特征的数据

参数

[输出] data: 特征数据

[输入] ri_id: 运行实例的ID

[输入] output_index: 输出的索引

[输入] work: 处理数据的方式,查看 ::DATA_WORK.

说明

与HbrtRiGetFeatureData相似,但是给出了输出索引而不是特征句柄。


函数原型

hbrt_error_t hbrtUnquantize(float *to_float_data, hbrt_element_type_t from_int_element_type, hbrt_dimension_t dim, const uint8_t *shifts, const void *from_int_data);

功能

反量化数据

参数

[输出] to_float_data: 反量化的浮点数据将被写入此地址

[输入] from_int_element_type: 原始整数类型

[输入] dim: 原始数据的维度,应该是有4个元素的uint32类型的数组

[输入] shifts: 数据的移位值

[输入] from_int_data: 源数据的地址

说明


函数原型

hbrt_error_t hbrtUnquantizeByScale(float *to_float_data, hbrt_element_type_t from_int_element_type, hbrt_dimension_t dim, const float *scales, const void *from_int_data);

功能

按照缩放值反量化数据。

参数

[输出] to_float_data:反量化浮点数据将会写入该地址。

[输入] from_int_element_type:源数据的元素类型。

[输入] dim:源数据的维度。应为4个uint32元素的数组。

[输入] scales:数据的缩放值。

[输入] from_int_data:源数据的地址。

说明


函数原型

hbrt_error_t hbrtQuantize(void *to_int_data, hbrt_element_type_t to_int_element_type, hbrt_dimension_t dim, const uint8_t *shifts, const float *from_float_data);

功能

量化数据

参数

[输出] to_int_data: 量化的整数数据将被写入此地址

[输入] to_int_element_type: 目标整数类型

[输入] dim: 源数据的维度,应该是有4个元素的uint32类型的数组

[输入] shifts: 数据的移位值

[输入] from_float_data: 源数据的地址

说明


函数原型

hbrt_error_t hbrtQuantizeByScale(void *to_int_data, hbrt_element_type_t to_int_element_type, hbrt_dimension_t dim, const float *scales, const float *from_float_data);

功能

按照缩放值量化数据。

参数

[输出] to_int_data:量化整数数据将会写入该地址。

[输入] to_int_element_type:目标元素类型。

[输入] dim: 源数据维度。应为包含4个uint32元素的数组。

[输入] scales: 数据缩放值。

[输入] from_float_data:源数据地址。

说明

10.2.7. 工具函数

10.2.7.1. 描述

软件包提供辅助函数,这些函数可以让用户转换不同的数据排布格式,记录funccall日志等功能。

10.2.7.2. 转换数据排布格式

函数原型

hbrt_error_t hbrtGetLayoutName(const char **name, hbrt_layout_type_t layout)

功能

提取给定数据排布类型的名字

参数

[输出] name: 排布类型的名字

[输入] layout: 排布的enum

说明


函数原型

hbrt_error_t hbrtConvertLayout(void *to_data, hbrt_layout_type_t to_layout_type, const void *from_data, hbrt_layout_type_t from_layout_type, hbrt_element_type_t element_type, hbrt_dimension_t aligned_dim, bool convert_endianness)

功能

转换输入数据排布格式

参数

[输出] to_data: 转换后的数据存储地址

[输入] to_layout_type: 目标数据排布

[输入] from_data: 源数据的地址

[输入] from_layout_type: 源数据的排布

[输入] element_type: 数据的数据类型

[输入] aligned_dim: 源数据的维度

[输入] convert_endianness: 如果为真,源数据字节序也会被转换

说明

对齐后的维度包含padding. 用户必须自己负责对齐数据,并传入函数。 输出数据的维度不会变化,因为这个函数至转换数据排布格式,并不改编维度大小。


函数原型

hbrt_error_t hbrtConvertLayoutRoi(void *to_data, hbrt_layout_type_t to_layout_type, const void *from_data, hbrt_layout_type_t from_layout_type, hbrt_element_type_t element_type, hbrt_dimension_t aligned_dim, bool convert_endianness, hbrt_roi_t roi)

功能

根据发给定的roi(coord, size)转换输入排布

参数

[输出] to_data: 转换后的数据存储地址

[输入] to_layout_type: 目标数据排布

[输入] from_data: 源数据的地址

[输入] from_layout_type: 源数据的排布

[输入] element_type: 数据的数据类型

[输入] aligned_dim: 源数据的维度

[输入] convert_endianness: 如果为真,源数据字节序也会被转换

[输入] roi: Roi(coord, size).

说明

对齐后的维度包含padding. 用户必须自己负责对齐数据,并传入函数。 输出数据的维度不会变化,因为这个函数至转换数据排布格式,并不改编维度大小。


函数原型

hbrt_error_t hbrtConvertLayoutToNative1HW1(void *to_data, const void *from_data, hbrt_layout_type_t from_layout_type, hbrt_element_type_t element_type, hbrt_dimension_t aligned_dim, bool convert_endianness, uint32_t n_index, uint32_t c_index)

功能

根据发给定的roi({n_index, 0, 0, c_index}, {1, H, W, 1})转换输入排布

参数

[输出] to_data: 转换后的数据存储地址

[输入] from_data: 源数据的地址

[输入] from_layout_type: 源数据的排布

[输入] element_type: 数据的数据类型

[输入] aligned_dim: 源数据的维度

[输入] convert_endianness: 如果为真,源数据字节序也会被转换

[输入] n_index: 要被转换数据的N维度的index

[输入] c_index: 要被转换数据的C维度的index

说明

对齐后的维度包含padding. 用户必须自己负责对齐数据,并传入函数。 对于给定的N和C,函数转换整个HxW平面


函数原型

hbrt_error t hbrtConvertLayoutToNative111C(void *to_data, const void *from_data, hbrt_layout_type_t from_layout_type, hbrt_element_type_t element_type, hbrt_dimension_t aligned_dim, bool convert_endianness, uint32_t n_index, uint32_t h_index, uint32_t w_index)

功能

根据发给定的roi({n_nidex, h_index, w_index, 0}, {1, 1, 1, C})转换输入排布

参数

[输出] to_data: 转换后的数据存储地址

[输入] from_data: 源数据的地址

[输入] from_layout_type: 源数据的排布

[输入] element_type: 数据的数据类型

[输入] aligned_dim: 源数据的维度

[输入] convert_endianness: 如果为真,源数据字节序也会被转换

[输入] n_index: 要被转换数据的N维度的index

[输入] h_index: 要被转换数据的H维度的index

[输入] w_index: 要被转换数据的W维度的index

说明

对齐后的维度包含padding. 用户必须自己负责对齐数据,并传入函数。 对于给定的N,H和W,函数转换整个C通道


函数原型

hbrt_error_t hbrtConvertLayoutToNative1111(void *to_data, const void *from_data, hbrt_layout_type_t from_layout_type, hbrt_element_type_t element_type, hbrt_dimension_t aligned_dim, bool convert_endianness, uint32_t n_index, uint32_t h_index, uint32_t w_index, uint32_t c_index)

功能

根据发给定的roi({n_nidex, h_index, w_index, c_index}, {1, 1, 1, 1})转换输入排布

参数

[输出] to_data: 转换后的数据存储地址

[输入] from_data: 源数据的地址

[输入] from_layout_type: 源数据的排布

[输入] element_type: 数据的数据类型

[输入] aligned_dim: 源数据的维度

[输入] convert_endianness: 如果为真,源数据字节序也会被转换

[输入] n_index: 要被转换数据的N维度的index

[输入] h_index: 要被转换数据的H维度的index

[输入] w_index: 要被转换数据的W维度的index

[输入] c_index: 要被转换数据的C维度的index

说明

对齐后的维度包含padding. 用户必须自己负责对齐数据,并传入函数。


函数原型

hbrt_error_t hbrtAddPadding(void *data_with_padding, hbrt_dimension_t dim_with_padding, const void *data_wo_padding, hbrt_dimension_t dim_wo_padding, hbrt_element_type_t element_type)

功能

给输入加上padding

参数

[输出] data_with_padding: 加上padding后的数据的地址

[输入] dim_with_padding: 加上padding后的维度

[输入] data_wo_padding: 没有padding的源数据

[输入] dim_wo_padding: 没有padding的源数据的维度

[输入] element_type: 源数据的数据类型

说明

用户自己负责完整性检查


函数原型

hbrt_error_t hbrtRemovePadding(void *data_wo_padding, hbrt_dimension_t dim_wo_padding, const void *data_with_padding, hbrt_dimension_t dim_with_padding, hbrt_element_type_t element_type)

功能

给输入去除padding

参数

[输出] data_with_padding: 去除padding后的数据的地址

[输入] dim_with_padding: 去除padding后的维度

[输入] data_wo_padding: 有padding的源数据

[输入] dim_wo_padding: 有padding的源数据的维度

[输入] element_type: 源数据的数据类型

说明


函数原型

hbrt_error_t hbrtConvertEndianness (void *output, const void *input, size_t size)

功能

转换输入的字节序

参数

[输出] output: 结果存储到这个地址

[输入] input: 源数据地址

[输入] size: 源数据字节数

说明

输入和输出不能重叠,除非它们有一样的地址


10.2.7.3. 日志记录

函数原型

hbrt_error_t hbrtSetLogLevel()

功能

设置记录详细级别

参数

说明

运行时日志记录详细级别是通过读取环境变量HBRT_LOG_LEVEL来设定的

总共有5个级别,从0到4:

    1. 无记录

    1. 记录重要的但是很少发生的事件。比如加载HBM

    1. 记录普遍的,但是很少发生的事件

    1. 记录重要的,且频繁发生的事件。比如生成funccall

    1. 记录普遍的,且频繁发生的事件


函数原型

hbrt_error_t hbrtPrintFunccall(const void *funccall)

功能

打印给定的funccall

参数

[输入] funccall: 包含funccall的缓存地址

说明

缓存可能包含多个funccall,多个funccall会按顺序打印

10.2.8. 特征量化类型

索引

特征量化类型

描述

0

QUANTIZED_BY_NONE

特征包含浮点值,不需要量化和反量化。

1

QUANTIZED_BY_SHIFT

特征包含定点数据,使用前需按照移位值反量化。

2

QUANTIZED_BY_SCALE

特征包含定点数据,使用前需按照缩放值反量化。


10.2.9. 状态码

索引

状态码

描述

0

hbrtSuccess

API调用返回没有错误

1

hbrtErrorCannotOpenFile

传递给API的文件路径无效

2

hbrtErrorHBMIdIsBusy

API尝试将一个hbm加载到已被另一个hbm占用的内存块中

3

hbrtErrorHBMSlotIsFull

已加载的hbm数量已超过限制

4

hbrtErrorHBMAlreadyLoaded

API正在尝试加载之前已加载的hbm

5

hbrtErrorHBMCCForDifferentMARCH

API正在尝试加载为其他微架构的编译的hbm

6

hbrtErrorHBMCRC32VerifyFail

crc32校验和与记录的内容不同

7

hbrtErrorMemoryAllocationFail

在API内部调用的malloc api返回null_ptr

8

hbrtErrorMemoryOverflow

传递给API的内存太小,无法包含数据

9

hbrtErrorNumericOverflow

API内部发生数字溢出

10

hbrtErrorIllegalCoreMask

传递给API的core-mask是非法的

11

hbrtErrorIllegalMARCH

传递给API的微架构或从hbm解码的微架构是非法的

12

hbrtErrorIllegalHBM

API的输入hbm非法

13

hbrtErrorIllegalHBMHandle

传递给API的hbm句柄是非法的

14

hbrtErrorIllegalElementType

传递给API或从hbm解码的元素类型是非法的

15

hbrtErrorIllegalInputSourceType

传递到API或从hbm解码的输入源是非法的

16

hbrtErrorIllegalRegionType

传递给API或从hbm解码的区域类型是非法的

17

hbrtErrorIllegalRIID

传递给API或从句柄获取的ri_id是非法的

18

hbrtErrorIllegalRegisterValue

从hbm解码或由运行时确定的寄存器值是非法的

19

hbrtErrorIllegalOutputRegion

传递给API或由运行时创建的输出区域是非法的

20

hbrtErrorIllegalIntermediateRegion

运行时创建的中间区域是非法的

21

hbrtErrorIllegalHeapRegion

运行时创建的堆区域是非法的

22

hbrtErrorIllegalRIConfig

传递到API或从句柄获取的RI配置是非法的

23

hbrtErrorIllegalRegisterType

从hbm解码的寄存器类型是非法的

24

hbrtErrorIllegalCPUOperator

从hbm解码的CPU操作参数是非法的

25

hbrtErrorIllegalLayout

传递给API或从句柄获取的数据排布是非法的

26

hbrtErrorIllegalMemoryRead

API内部发生了非法的内存访问

27

hbrtErrorIllegalModel

尝试执行无法被相应API访问的模型

28

hbrtErrorInvalidHBMHandle

传递给API的hbm句柄无效

29

hbrtErrorInvalidModelHandle

传递给API的输入模型句柄无效

30

hbrtErrorInvalidFeatureHandle

传递给API的特征张量句柄无效

31

hbrtErrorInvalidModelName

传递给API的模型名称无效,或者hbm不包含具有该名称的模型

32

hbrtErrorInvalidInputIndex

传递给API的输入索引无效或超过模型输入数

33

hbrtErrorInvalidOutputIndex

传递给API的输出索引无效或超过模型输出数

34

hbrtErrorInvalidBatchCount

从hbm解码的批计数无效

35

hbrtErrorInvalidSegmentIndex

从ri或其他结构获取的段索引无效

36

hbrtErrorInvalidInterruptNum

传递给API的中断号无效

37

hbrtErrorInvalidResizerParam

传递给API的缩放参数无效

38

hbrtErrorInvalidDataWork

传递给API的数据工作方式无效

39

hbrtErrorInvalidAddress

传递给API或从其他结构获取的地址无效

40

hbrtErrorInvalidRle

RLE解码期间发生错误

41

hbrtErrorInvalidRoi

传递给RoiAlign的ROI无效

42

hbrtErrorBPUCPUMemcpyFail

bpu_memcpy在API内部返回了非零值

43

hbrtErrorBPUMemAllocFail

bpu_mem_alloc在API内返回了null_ptr

44

hbrtErrorBPUCPUMemAllocFail

bpu_cpumem_alloc在API内返回了null_ptr

45

hbrtErrorRiIsNotInUse

传递给API的ri_id不与任何模型绑定

46

hbrtErrorRiIsInUse

API尝试以一个没有销毁的ri_id启动另一个运行实例

47

hbrtErrorFunccallSlotNotEnough

存储 Funccall 的内存太小,无法容纳生成的函数调用

48

hbrtErrorFunctionNotImplemented

当前版本尚未实现该API

49

hbrtErrorInvalidLicense

您的本地许可证不允许访问此HBM

50

hbrtErrorIncompatibleVersion

头文件或HBM的版本与当前的运行时库不兼容

51

hbrtErrorInvalidMemoryPool

HBDK运行时内存池中发生错误

52

hbrtErrorAccessToEmptyData

尝试存储不存在的数据或空数据

10.3. VIO API

VIO API 参见《MU-2020-1-C-X2J2平台系统软件接口手册》。