EASY EAI灵眸科技 | 让边缘AI落地更简单 (easy-eai.com)
产品简介
支持4路1080P@30fps视频流采集,四核CPU@1.5GHz与2Tops AI边缘算力能力。集成有以太网、Wi-Fi、4G等网络通信外设;RS232、RS485、UART等本地通信接口。HDMI显示屏接口、音频输入输出等交互外设。2路USB Host接口、2路Type-C调试接口。继电器、指示灯、TF卡、按键等通用外设。可内置人员闯入识别、人数检测、火焰检测、安全帽识别、聚众识别等各类AI算法,并支持ubuntu系统供客户二次开发
实物接线
入门指南
电源
编译环境
产品调试方式
ADB
串口
网络
开发方式
交叉编译
优点:
采用x86架构的CPU进行编译,编译速度快。
源码编辑方便,开发环境支持各种如vsCode、qtCreator等IDE。
缺点:
编译环境需要进行安装部署。
程序的调试运行操作相对本地编译不那么直接。
固件烧录
异常情况直接查文档
AI算法组件
AI算法开发流程
模型转换工具搭建
执行以下指令加载模型转换工具docker镜像:
docker load --input /home/developer/rknn-toolkit/rknn-toolkit-1.7.3-docker.tar.gz
执行以下指令进入镜像bash环境:
docker run -t -i --privileged -v /dev/bus/usb:/dev/bus/usb rknn-toolkit:1.7.3 /bin/bash
输入“python”加载python相关库,尝试加载rknn库,如下图环境测试成功:
模型转换示例
执行以下指令把工作区域映射进docker镜像,其中/home/developer/rknn-toolkit/model_convert为工作区域,/test为映射到docker镜像,/dev/bus/usb:/dev/bus/usb为映射usb到docker镜像:
docker run -t -i --privileged -v /dev/bus/usb:/dev/bus/usb -v /home/developer/rknn-toolkit/model_convert:/test rknn-toolkit:1.7.3 /bin/bash
在docker环境切换到模型转换工作目录:
cd /test/coco_object_detect/
执行gen_list.py生成量化图片列表:
python gen_list.py
生成“量化图片列表”如下文件夹所示:
在执行rknn_convert.py脚本进行模型转换:
python rknn_convert.py
生成模型如下图所示,此模型可以在rknn环境和EAI-BOX1000环境运行:
用yolov5_coco_test.py脚本在PC端的环境下可以运行rknn的模型
执行yolov5_coco_test.py脚本测试rknn模型:
python yolov5_coco_test.py
由于rknn模型用NPU API在EAI-BOX1000加载的时候启动速度会好慢,在评估完模型精度没问题的情况下,建议进行模型预编译。预编译的时候需要通过EAI-BOX1000主板的环境,所以请务必接上adb口与ubuntu保证稳定连接。
虚拟机要保证接上adb设备:
由于在虚拟机里ubuntu环境与docker环境对adb设备资源是竞争关系,所以需要关掉ubuntu环境下的adb服务,且在docker里面通过apt-get安装adb软件包。以下指令在ubuntu环境与docker环境里各自执行:
在docker环境里执行adb devices,现象如下图所示则设备连接成功:
运行precompile_rknn.py脚本把模型执行预编译:
python precompile_rknn.py
至此预编译部署完成,模型转换步骤已全部完成。生成如下预编译后的int8量化模型:
模型转换API
RKNN 模型配置
API | config |
描述 | 设置模型参数 |
参数 | batch_size:批处理大小,默认值为 100。量化时将根据该参数决定每一批次参与运算的数据量,以校正量化结果。如果dataset中的数据量小于batch_size,则该参数值将自动调整为dataset中的数据量。如果量化时出现内存不足的问题,建议将这个值设小一点,例如 8。 |
mean_values:输入的均值。该参数与 channel_mean_value参数不能同时设置。参数格式是一个列表,列表中包含一个或多个均值子列表,多输入模型对应多个子列表,每个子列表的长度与该输入的通道数一致,例如[[128,128,128]],表示一个输入的三个通道的值减去128。如果 reorder_channel设置成’2 1 0‘,则优先做通道调整,再做减均值。 | |
std_values:输入的归一化值。该参数与channel_mean_value参数不能同时设置。参数格式是一个列表,列表中包含一个或多个归一化值子列表,多输入模型对应多个子列表,每个子列表的长度与该输入的通道数一致,例如[[128,128,128]],表示设置一个输入的三个通道的值减去均值后再除以128。如果 reorder_channel设置成’2 1 0‘,则优先做通道调整,再减均值和除以归一化值。 | |
epochs:量化时的迭代次数,每迭代一次,就选择 batch_size 指定数量的图片进行量化校正。默认值为-1,此时 RKNN-Toolkit 会根据dataset中的图片数量自动计算迭代次数以最大化利用数据集中的数据。 | |
reorder_channel:表示是否需要对图像通道顺序进行调整,只对三通道输入有效。’0 1 2’表示按照输入的通道顺序来推理,比如图片输入时是 RGB,那推理的时候就根据 RGB顺序传给输入层;’2 1 0’表示会对输入做通道转换,比如输入时通道顺序是RGB,推理时会将其转成 BGR,再传给输入层,同样的,输入时通道的顺序为 BGR 的话,会被转成 RGB 后再传给输入层。如果有多个输入,每个输入的参数以“#”进行分 隔,如 ’0 1 2#0 1 2’。该参数的默认值是 None,对于 Caffe 框架的三通道输入模型,表示需要做通道顺序的调整,其他框架的三通道输入模型,默认不做通道顺序调整。 | |
need_horizontal_merge:是否需要进行水平合并,默认值为 False。如果模型是 inception v1/v3/v4,建议开启该选项,可以提高推理时的性能。 | |
quantized_dtype:量化类型,目前支持的量化类型有 asymmetric_quantized-u8、dynamic_fixed_point-i8、dynamic_fixed_point-i16,默认值为 asymmetric_quantized-u8。 | |
quantized_algorithm: 量化参数优化算法。当前版本支持的算法有:normal,mmse和kl_divergence,默认值为normal。其中normal 算法的特点是速度较快。而mmse算 法,因为需要对量化参数进行多次调整,其速度会慢很多,但通常能得到比normal算法更高的精度;kl_divergence所用时间会比 normal多一些,但比 mmse 会少很多,在某些场景下可以得到较好的改善效果。 | |
mmse_epoch:mmse量化算法的迭代次数,默认值为 3。通常情况下,迭代次数越多,精度往往越高。 | |
optimization_level:模型优化等级。通过修改模型优化等级,可以关掉部分或全部模型转换过程中使用到的优化规则。该参数的默认值为 3,打开所有优化选项。值为2或1时关闭一部分可能会对部分模型精度产生影响的优化选项,值为0时关闭所有 优化选项。 | |
target_platform:指定RKNN模型目标运行平台。目前支持RK1806、RK1808、RK3399Pro、RV1109和RV1126。其中基于RK1806、RK1808 或 RK3399Pro生成的RKNN模型可以在这三个平台上通用,基于 RV1109或RV1126生成的RKNN模型可以在这两个平台通用。如果模型要在RK1806、RK1808或RK3399Pro上运行,该参数的值可以是 [“rk1806”], [“rk1808”], [“rk3399pro”]或 [“rk1806”, “rk1808”, “rk3399pro”]等;如果模型要在RV1109 或 RV1126 上运行,该参数的值可以是 [“rv1126”], [“rv1109”]或[“rv1109”, “rv1126”]等。这个参数的值不可以是类似[“rk1808”, “rv1126”]这样的组合,因为这两款芯片互不兼容。如果不填该参数,则默认是 [“rk1808”],生成的RKNN 模型可以在 RK1806、RK1808和RK3399Pro 平台上运行。 该参数的值大小写不敏感。 | |
quantize_input_node: 开启后无论模型是否量化,均强制对模型的输入节点进行量化。 输入节点被量化的模型,在部署时会有性能优势,rknn_input_set接口的耗时更少。当 RKNN-Toolkit 量化没有按理想情况对输入节点进行量化(仅支持输入为图片的模型)、或用户选择加载深度学习框架已生成的量化模型时可以启用(这种情况下,第一层的quantize_layer会被合并到输入节点)。默认值为 False。 | |
merge_dequant_layer_and_output_node: 将模型输出节点与上一层的dequantize_layer,合并成一个被量化的输出节点,允许模型在部署时返回 uint8或 float类型的推理结果。此配置仅对加载深度学习框架已生成的量化模型有效。默认为 False。 | |
返回值 | 无 |
模型加载
ONNX 模型加载
API | load_onnx |
描述 | 加载ONNX模型 |
参数 | model:ONNX模型文件(.onnx 后缀)所在路径。 |
inputs:指定模型的输入节点,数据类型为列表。例如示例中的 resnet50v2模型,其输入节点是['data']。默认值是 None,此时工具自动从模型中查找输入节点。可选参数。 | |
input_size_list:每个输入节点对应的数据形状。例如示例中的 resnet50v2模型,其输入节点对应的输入尺寸是[[3, 224, 224]]。可选参数。 注:1. 填写输入数据形状时不要填 batch 维。如果要批量推理,请使用 build 接口的 rknn_batch_size 参数。 2. 如果指定了 inputs 节点,则该参数必须填写。 | |
outputs:指定模型的输出节点,数据类型为列表。例如示例中的 resnet50v2模型,其 输出节点是['resnetv24_dense0_fwd']。默认值是 None,此时工具将自动从模型中搜索输出节点。可选参数。 | |
返回值 | 0:导入成功 |
-1:导入失败 |
PyTorch 模型加载接口
API | load_pytorch |
描述 | 加载 PyTorch模型 |
参数 | model:PyTorch模型文件(.pt后缀)所在路径,而且需要是 torchscript格式的模型。 必填参数。 |
input_size_list :每个输入节点对应的图片的尺寸和通道数。例如 [[1,224,224],[ 3,224,224]]表示有两个输入,其中一个输入的 shape 是[1,224,224],另外一个输入的 shape是[3,224,224]。必填参数。 | |
返回值 | 0:导入成功 |
-1:导入失败 |
构建 RKNN 模型
API | build |
描述 | 依照加载的模型结构及权重数据,构建对应的 RKNN模型。 |
参数 | do_quantization:是否对模型进行量化,值为 True或 False。 |
dataset:量化校正数据的数据集。目前支持文本文件格式,用户可以把用于校正的图片(jpg或 png格式)或 npy文件路径放到一个.txt 文件中。文本文件里每一行一条路径信息。如: a.jpg b.jpg 或 a.npy b.npy 如有多个输入,则每个输入对应的文件用空格隔开,如: a.jpg a2.jpg b.jpg b2.jpg 或 a.npy a2.npy b.npy b2.npy | |
pre_compile:模型预编译开关。预编译 RKNN 模型可以减少模型初始化时间,但是无法通过模拟器进行推理或性能评估。如果 NPU 驱动有更新,预编译模型通常也需要重新构建。 注: 1. 该选项只在 Linux x86_64 平台上有效。 2. RKNN-Toolkit-V1.0.0 及以上版本生成的预编译模型不能在 NPU 驱动版本小于 0.9.6 的设备上运行;RKNN-Toolkit-V1.0.0 以前版本生成的预编译模型不能在NPU 驱 动 版 本 大 于 等 于 0.9.6 的 设 备 上 运 行 。 驱 动 版 本 号 可 以 通 过get_sdk_version 接口查询。 | |
rknn_batch_size:模型的输入 Batch 参数调整,默认值为 1。如果大于 1,则可以在一次推理中同时推理多帧输入图像或输入数据,如 MobileNet 模型的原始input 维度为[1, 224, 224, 3],output 维度为[1, 1001],当 rknn_batch_size 设为 4 时,input 的维度变为[4, 224, 224, 3],output 维度变为[4, 1001]。 注: 1. rknn_batch_size 的调整并不会提高一般模型在 NPU 上的执行性能,但却会显著增加内存消耗以及增加单帧的延迟。 2. rknn_batch_size 的调整可以降低超小模型在 CPU 上的消耗,提高超小模型的平均帧率。(适用于模型太小,CPU 的开销大于 NPU 的开销)。 3. rknn_batch_size 的值建议小于 32,避免内存占用太大而导致推理失败。 4. rknn_batch_size 修改后,模型的 input/output 维度会被修改,使用 inference 推理模型时需要设置相应的 input 的大小,后处理时,也需要对返回的 outputs 进行处理。 | |
返回值 | 0:构建成功 |
-1:构建失败 |
导出 RKNN 模型
通过该接口导出 RKNN 模型文件,用于模型部署。
API | export_rknn |
描述 | 将 RKNN模型保存到指定文件中(.rknn 后缀)。 |
参数 | export_path:导出模型文件的路径。 |
返回值 | 0:导入成功 ; |
-1:导入失败 |
加载 RKNN模型
API | load_rknn |
描述 | 加载 RKNN 模型。 |
参数 | path:RKNN模型文件路径。 |
load_model_in_npu:是否直接加载npu中的rknn模型。其中path为rknn 模型在npu中的路径。只有当RKNN-Toolkit运行在RK3399Pro Linux 开发板或连有 NPU 设备 的 PC 上时才可以设为 True。默认值为 False。 | |
返回值 | 0:导入成功 ; |
-1:导入失败 |
初始化运行时环境
在模型推理或性能评估之前,必须先初始化运行时环境,明确模型在的运行平台(具体的目标硬件平台或软件模拟器)
API | init_runtime |
描述 | 初始化运行时环境。确定模型运行的设备信息(硬件平台信息、设备 ID);性能评估时是否启用debug 模式,以获取更详细的性能信息。 |
参数 | target:目标硬件平台,目前支持“rk3399pro”、“rk1806”、“rk1808”、“rv1109”、 “rv1126”。默认为 None,即在 PC 使用工具时,模型在模拟器上运行,在RK3399Pro Linux 开发板运行时,模型在RK3399Pro自带NPU上运行,否则在设定的target上 运行。其中“rk1808”包含了TB-RK1808 AI 计算棒。 |
device_id:设备编号,如果PC连接多台设备时,需要指定该参数,设备编号可以通过”list_devices”接口查看。默认值为 None。 注:MAC OS X 系统当前版本还不支持多个设备。 | |
perf_debug:进行性能评估时是否开启debug 模式。在 debug 模式下,可以获取到每一层的运行时间,否则只能获取模型运行的总时间。默认值为 False。 | |
eval_mem: 是否进入内存评估模式。进入内存评估模式后,可以调用 eval_memory 接口获取模型运行时的内存使用情况。默认值为 False。 | |
async_mode:是否使用异步模式。调用推理接口时,涉及设置输入图片、模型推理、获取推理结果三个阶段。如果开启了异步模式,设置当前帧的输入将与推理上一帧同时进行,所以除第一帧外,之后的每一帧都可以隐藏设置输入的时间,从而提升性能。 在异步模式下,每次返回的推理结果都是上一帧的。该参数的默认值为 False。 | |
返回值 | 0:构建成功 |
-1:构建失败 |
模型推理
在进行模型推理前,必须先构建或加载一个 RKNN 模型。
API | inference |
描述 | 对当前模型进行推理,返回推理结果。 如果 RKNN-Toolkit运行在PC上,且初始化运行环境时设置 target 为Rockchip NPU设备,得到的是模型在硬件平台上的推理结果。 如果 RKNN-Toolkit 运行在PC上,且初始化运行环境时没有设置 target,得到的是模型在模拟器上的推理结果。模拟器可以模拟 RK1808,也可以模拟RV1126,具体模拟哪款芯片,取决于RKNN 模型的 target_platform 参数值. 如果 RKNN-Toolkit运行在 RK3399Pro Linux开发板上,得到的是模型在实际硬件上的推理结果。 |
参数 | inputs:待推理的输入,如经过 cv2 处理的图片。格式是 ndarray list。 |
data_type:输入数据的类型,可填以下值:’float32’, ‘float16’, ‘int8’, ‘uint8’, ‘int16’。默认值为’uint8’。 | |
data_format:数据模式,可以填以下值: “nchw”, “nhwc”。默认值为’nhwc’。这两个的 不同之处在于 channel 放置的位置。 | |
inputs_pass_through:将输入透传给NPU 驱动。非透传模式下,在将输入传给NPU驱动之前,工具会对输入进行减均值、除方差等操作;而透传模式下,不会做这些操作。这个参数的值是一个数组,比如要透传input0,不透彻input1,则这个参数的值为[1, 0]。默认值为None,即对所有输入都不透传。 | |
返回值 | results:推理结果,类型是 ndarray list。 |
模型性能评估
API | eval_perf |
描述 | 评估模型性能。模型运行在PC上,初始化运行环境时不指定 target,得到的是模型在模拟器上运行的性能数据,包含逐层的运行时间及模型完整运行一次需要的时间。模拟器可以模拟 RK1808,也可以模拟 RV1126,具体模拟哪款芯片,取决于RKNN模型的target_platform参数值。 模型运行在与PC连接的Rockchip NPU上,且初始化运行环境时设置perf_debug为False,则获得的是模型在硬件上运行的总时间;如果设置perf_debug为 True,除了返回总时间外,还将返回每一层的耗时情况。模型运行在RK3399Pro Linux开发板上时,如果初始化运行环境时设置perf_debug为False,获得的也是模型在硬件上运行的总时间;如果设置perf_debug为 True,返回总时间及每一层的耗时情况 |
参数 | loop_cnt: 指定RKNN模型推理次数,用于计算平均推理时间。该参数只在init_runtime中的 target为非模拟器,且perf_debug设成 False时生效。该参数数据类型为整型,默认值为 1。 |
返回值 | perf_result:性能评估结果,详细说明请参考 5.3 章节。 |
量化精度分析
API | accuracy_analysis |
描述 | 逐层对比浮点模型和量化模型的输出结果,输出余弦距离和欧式距离,用于分析量化模型精度下降原因。 注: 1.该接口在build或hybrid_quantization_step1或 hybrid_quantization_step2之后调用,并且原始模型应该为浮点模型,否则会调用失败。 2. 该接口使用的量化方式与 config 中指定的一致。 |
参数 | inputs:包含输入图像或数据的数据集文本文件(与量化校正数据集 dataset 格式相同, 但只能包含一组输入)。 |
output_dir:输出目录,所有快照都保存在该目录。该目录内容的详细说明见 4.3.3 章 节。 | |
calc_qnt_error:是否计算量化误差(默认为 True)。 | |
target: 指定设备类型。如果指定 target,在逐层量化误差分析时,将连接到 NPU上获取每一层的真实结果,跟浮点模型结果相比较。这样可以更准确的反映实际运行时的误差。 | |
device_id: 如果 PC 连接了多个NPU设备,需要指定具体的设备编号。 | |
dump_file_type: 精度分析过程中会输出模型每一层的结果,这个参数指定了输出文件的类型。有效值为’tensor’和’npy’,默认值是’tensor’。如果指定数据类型为’npy’, 可以减少精度分析的耗时。 | |
返回值 | 0:成功 |
-1:失败 |
导出预编译模型(在线预编译)
构建RKNN模型时,可以指定预编译选项以导出预编译模型,这被称为离线编译。同样,RKNN Toolkit 也提供在线编译的接口:export_rknn_precompile_model。使用该接口,可以将普通 RKNN 模型转成预编译模型。
API | export_rknn_precompile_model |
描述 | 经过在线编译后导出预编译模型。 注: 1. 使用该接口前必须先调用 load_rknn 接口加载普通 rknn 模型; 2. 使用该接口前必须调用 init_runtime 接口初始化模型运行环境,target 必须是RK NPU 设备,不能是模拟器;而且要设置 rknn2precompile 参数为 True。 |
参数 | export_path: 导出模型路径。必填参数。 |
返回值 | 0:成功 -1:失败 |
模型部署示例
在EASY-EAI编译环境下,在例程目录执行以下指令把可执行程序推送到开发板端:
cp yolov5_detect_demo_release/ /mnt/userdata/ -rf
通过按键Ctrl+Shift+T创建一个新窗口,执行adb shell命令,进入板卡运行环境:
adb shell
进入板卡后,定位到例程上传的位置,如下所示:
cd /userdata/yolov5_detect_demo_release/
运行例程命令如下所示:
./yolov5_detect_demo
执行结果如下图所示:
退出板卡环境,取回测试图片:
exit
adb pull /userdata/yolov5_detect_demo_release/result.jpg .
模型部署API
量化和反量化
零拷贝
针对 RGB 或 BGR 输入数据,实现 输入零拷贝的步骤如下:
1)三个通道的均值是相同的整数同时归一化的缩放因子相同。
2)在 rknn-toolkit 的 config 函数中,设置 force_builtin_perm=True,导出 NHWC输入的 RKNN 模型。
3)使用 rknn_inputs_map 接口,获取输入 tensor 内存地址信息。
4)往内存地址填充输入数据,比如调用 RGA 缩放函数,目标地址使用 rknn_inputs_map获取的物理地址。
5)调用 rknn_inputs_sync 接口。
6)调用 rknn_run 接口。
7)调用获取输出接口。
API详细说明
rknn_init
rknn_init初始化函数将创建 rknn_context 对象、加载 RKNN 模型以及根据 flag执行 特定的初始化行为。
API | rknn_init |
功能 | 初始化 rknn |
参数 | rknn_context *context:rknn_context指针。函数调用之后,context 将会被赋值。 |
void *model:RKNN 模型的二进制数据。 | |
uint32_t size:模型大小。 | |
uint32_t flag:特定的初始化标志。目前 RK1808 平台仅支持以下标志: RKNN_FLAG_COLLECT_PERF_MASK:打开性能收集调试开关,打开之后能够通过rknn_query 接口查询网络每层运行时间。需要注意,该标志被设置后rknn_run的运行时间将会变长。 | |
返回值 | int错误码(见rknn 返回值错误码)。 |
rknn_destroy
rknn_destroy 函数将释放传入的 rknn_context及其相关资源。
API | rknn_destroy |
功能 | 销毁 rknn_context 对象及其相关资源。 |
参数 | rknn_context context:要销毁的 rknn_context 对象。 |
返回值 | int 错误码(见 rknn 返回值错误码)。 |
rknn_query
rknn_query 函数能够查询获取到模型输入输出、运行时间以及 SDK 版本等信息。
API | rknn_query |
功能 | 查询模型与 SDK 的相关信息。 |
参数 | rknn_context context:rknn_context 对象。 |
rknn_query_cmd cmd:查询命令。 | |
void* info:存放返回结果的结构体变量。 | |
uint32_t size:info 对应的结构体变量的大小。 | |
返回值 | int 错误码(见 rknn 返回值错误码) |
rknn_run
rknn_run函数将执行一次模型推理,调用之前需要先通过rknn_inputs_set函数设置输入数据。
API | rknn_run |
功能 | 执行一次模型推理。 |
参数 | rknn_context context:rknn_context 对象。 |
rknn_run_extend* extend:保留扩展,当前没有使用,传入 NULL 即可。 | |
返回值 | int 错误码(见 rknn 返回值错误码) |
未完待续 ...