目前 RKNN-Toolkit 可以运行在 PC(Linux/Windows/MacOS x64)上,也可以运行在 RK3399Pro
开发板(Debian9 或 Debian10)。
本人推荐PC是linux系统,rk3399pro是debian10,原因之后补充。
该场景下,RKNN-Toolkit 运行在 PC 上,通过 PC 的 USB 连接 NPU 设备。RKNN-Toolkit 将RKNN 模型传到 NPU 设备上运行,再从 NPU 设备上获取推理结果、性能信息等。
当模型为非 RKNN 模型(Caffe、TensorFlow、TensorFlow Lite、ONNX、Darknet、PyTorch、
MXNet 等模型)时,RKNN-Toolkit 工具的使用流程及注意事项如下:
注:
1、 以上步骤请按顺序执行。
2、 蓝色框标注的步骤导出的 RKNN 模型可以通过 load_rknn 接口导入并使用。
3、 红色框标注的模型推理、性能评估和内存评估的步骤先后顺序不固定,根据实际使用情况
决定。
4、 只有当目标平台是 Rockchip NPU 时,才可以调用 eval_memory 接口获取内存使用情况。
该场景下,首先需要完成以下两个步骤:
1、 确保开发板的 USB OTG 连接到 PC,并且正确识别到设备,即在 PC 上调用 以下命令可以查询到相关设备。
python3 -m rknn.bin.list_devices
2、 调用 init_runtime 接口初始化运行环境时需要指定 target 参数和 device_id 参数。其中 target参数表明硬件类型,当前版本可选值为“rk1806”、“rk1808”、“rk3399pro”、“rv1109”或“rv1126”。当 PC 连接多个设备时,还需要指定 device_id 参数,即设备编号,设备编号可以通过 list_devices
接口或 python3 -m rknn.bin.list_devices
命令查询,示例如下:
all device(s) with adb mode:
[]
all device(s) with ntb mode:
[‘TB-RK1808S0’, ‘515e9b401c060c0b’]
初始化运行时环境代码示例如下:
# RK3399Pro
ret = init_runtime(target=’rk3399pro’, device_id=’VGEJY9PW7T’)
注:
SDK/platform-tools/update_rk_usb_rule/linux/update_rk1808_usb_rule.sh
脚本完成,详细说明请参考同级目录下的 README.txt。该场景下,RKNN-Toolkit 直接安装在 RK3399Pro Linux 系统中。构建或导入的 RKNN 模型直
接在 RK3399Pro 上运行,以获取模型实际的推理结果或性能信息。
对于 RK3399Pro Linux 开发板,RKNN-Toolkit 工具的使用流程取决于模型种类,如果模型类型是非 RKNN 模型,则使用流程同场景一中的第一个图;否则使用流程同第二个图。
本人使用的是pytorch模型,以下是加载 pytorch模型的示例代码,如果在 PC 上执行这个例子,RKNN 模型将在模拟器上运行:
import numpy as np
import cv2
from rknn.api import RKNN
import torchvision.models as models
import torch
# 通过跟踪转换为 Torch 脚本
# 要将 PyTorch 模型通过跟踪转换为 Torch 脚本,必须将模型的实例以及示例输入传递给torch.jit.trace函数
def export_pytorch_model():
net = models.resnet18(pretrained=True) # 换成你的模型
net.eval()
trace_model = torch.jit.trace(net, torch.Tensor(1,3,224,224))
trace_model.save('./resnet18.pt')
# show一下输出
def show_outputs(output):
output_sorted = sorted(output, reverse=True)
top5_str = '\n-----TOP 5-----\n'
for i in range(5):
value = output_sorted[i]
index = np.where(output == value)
for j in range(len(index)):
if (i + j) >= 5:
break
if value > 0:
topi = '{}: {}\n'.format(index[j], value)
else:
topi = '-1: 0.0\n'
top5_str += topi
print(top5_str)
def show_perfs(perfs):
perfs = 'perfs: {}\n'.format(perfs)
print(perfs)
def softmax(x):
return np.exp(x)/sum(np.exp(x))
def pytorch2rknn_predict():
export_pytorch_model()
model = './resnet18.pt'
input_size_list = [[3, 224, 224]]
# Create RKNN object
rknn = RKNN()
# rknn = RKNN(verbose=True, verbose_file=’./mobilenet_build.log’) # 将详细的日志信息输出到屏幕,并写到 mobilenet_build.log 文件中
# rknn = RKNN(verbose=True) # 只在屏幕打印详细的日志信息
# pre-process config
print('--> Config model')
rknn.config(mean_values=[[123.675, 116.28, 103.53]], std_values=[[58.395, 58.395, 58.395]], reorder_channel='0 1 2')
'''
rknn.config(mean_values=[[103.94, 116.78, 123.68]],
std_values=[[58.82, 58.82, 58.82]],
reorder_channel=’0 1 2’,
need_horizontal_merge=True,
target_platform=[‘rk1808’, ‘rk3399pro’])
'''
print('done')
# Load Pytorch model
print('--> Loading model')
ret = rknn.load_pytorch(model=model, input_size_list=input_size_list)
if ret != 0:
print('Load Pytorch model failed!')
exit(ret)
print('done')
# Build model
print('--> Building model')
ret = rknn.build(do_quantization=True, dataset='./dataset.txt') # dataset.txt 是一个包含测试图片路径的文本文件
if ret != 0:
print('Build model failed!')
exit(ret)
print('done')
# 量化精度分析
print('--> Accuracy analysis')
rknn.accuracy_analysis(inputs='./dataset.txt', target='rk3399pro')
print('done')
# Export RKNN model
print('--> Export RKNN model')
ret = rknn.export_rknn('./resnet_18.rknn') # 导出储存为 RKNN 模型文件,用于模型部署
if ret != 0:
print('Export resnet_18.rknn failed!')
exit(ret)
print('done')
# ret = rknn.load_rknn('./resnet_18.rknn') # 改为自己的rknn模型
# Set inputs
img = cv2.imread('./space_shuttle_224.jpg') # 预测的图片
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# Init runtime environment
print('--> Init runtime environment')
ret = rknn.init_runtime() # ret = rknn.init_runtime(target='rk3399pro', device_id='VGEJY9PW7T')
if ret != 0:
print('Init runtime environment failed')
exit(ret)
print('done')
# Inference
print('--> Running model')
outputs = rknn.inference(inputs=[img])
show_outputs(softmax(np.array(outputs[0][0]))) # 打印结果
print('done')
# perf 评估模型性能
print(‘→ Begin evaluate model performance’)
perf_results = rknn.eval_perf(inputs=[img])
print(‘done’)
rknn.release()
def main():
# export_pytorch_model()
pytorch2rknn_predict()
# rknn_predict()
if __name__ == '__main__':
main()
构建 RKNN 模型APIbuild
# 构建 RKNN 模型,并且做量化
ret = rknn.build(do_quantization=True, dataset='./dataset.txt')
dataset:量化校正数据的数据集。目前支持文本文件格式,用户可以把用于校正的图片(jpg 或 png 格式)或 npy 文件路径放到一个.txt 文件中。文本文件里每一行一条路径信息。
pre_compile:预编译开关,如果设置成 True,可以减小模型大小,及模型在硬件设备上的首次启动速度。但是打开这个开关后,构建出来的模型就只能在硬件平台上运行,无法通过模拟器进行推理或性能评估。如果硬件有更新,则对应的模型要重新构建。
注:
加载 RKNN 模型load_rknn
# 从当前路径加载 mobilenet_v1.rknn 模型
ret = rknn.load_rknn(path='./mobilenet_v1.rknn')
参数load_model_in_npu: 是否直接加载 npu 中的 rknn 模型。其中 path 为 rknn 模型在 npu中的路径。只有当 RKNN-Toolkit 运RK3399Pro Linux 开发板或连有 NPU 设备的 PC 上时才可以设为 True。默认值为 False。
模型推理API:inference
在进行模型推理前,必须先构建或加载一个 RKNN 模型。
对当前模型进行推理,返回推理结果。
如果 RKNN-Toolkit 运行在 PC 上,且初始化运行环境时设置 target 为 Rockchip NPU设备,得到的是模型在硬件平台上的推理结果。
如果 RKNN-Toolkit 运行在 PC 上,且初始化运行环境时没有设置 target,得到的是模型在模拟器上的推理结果。模拟器可以模拟 RK1808,也可以模拟 RV1126,具体模拟哪款芯片,取决于 RKNN 模型的 target_platform 参数值.
如果 RKNN-Toolkit 运行在 RK3399Pro Linux 开发板上,得到的是模型在实际硬件上的推理结果。
data_format:数据模式,可以填以下值: “nchw”, “nhwc”。默认值为’nhwc’。这两个的不同之处在于 channel 放置的位置。
评估模型性能API: eval_perf
# 对模型性能进行评估
……
rknn.eval_perf(inputs=[image], is_print=True)
……
评估模型性能。
模型运行在 PC 上,初始化运行环境时不指定 target,得到的是模型在模拟器上运行的性能数据,包含逐层的运行时间及模型完整运行一次需要的时间。模拟器可以模拟RK1808,也可以模拟 RV1126,具体模拟哪款芯片,取决于 RKNN 模型的 target_platform参数值。
模型运行在与 PC 连接的 Rockchip NPU 上,且初始化运行环境时设置 perf_debug 为 False,则获得的是模型在硬件上运行的总时间;如果设置 perf_debug 为 True,除了返回总时间外,还将返回每一层的耗时情况。
模型运行在 RK3399Pro Linux 开发板上时,如果初始化运行环境时设置 perf_debug 为 False,获得的也是模型在硬件上运行的总时间;如果设置 perf_debug 为 True,返回总时间及每一层的耗时情况
量化精度分析API:accuracy_analysis
使用浮点和量化模型推理并将每一层的结果做快照。之后再根据快照里的数据,比较量化模型和浮点模型每一层的差距,用于评估量化所产生的误差或错误。
注:
rknn.accuracy_analysis(inputs='./dataset.txt', target='rk3399pro')
导出加密模型API: export_encrypted_rknn_model
该接口的功能是将普通的 RKNN 模型按一定的算法进行加密。
注:
input_model: 待加密的 RKNN 模型路径。数据类型为字符串。必填参数。
output_model: 模型加密后的保存路径。数据类型为字符串。选填参数,如果不填该参数,则使用{original_model_name}.crypt.rknn 作为加密后的模型的名字。
crypt_level: 加密等级。等级越高,安全性越高,解密越耗时;反之,安全性越低,解密越快。数据类型为整型,默认值为 1,目前安全等级有 3 个等级,1,2 和 3。
from rknn.api import RKNN
if __name__ == '__main__':
rknn = RKNN()
ret = rknn.export_encrypted_rknn_model('test.rknn')
if ret != 0:
print('Encrypt RKNN model failed.')
exit(ret)
rknn.release()
获取设备列表API:list_devices
列出已连接的 RK3399PRO/RK1808/RV1109/RV1126 或 TB-RK1808 AI 计算棒。
注:目前设备连接模式有两种:ADB 和 NTB。其中 RK3399PRO 目前只支持 ADB 模式,TB-RK1808 AI 计算棒只支持 NTB 模式,RK1808/RV1109 支持 ADB/NTB 模式。多设备连接时请确保他们的模式都是一样的。
返回 adb_devices 列表和 ntb_devices 列表,如果设备为空,则返回空列表。例如我们的环境里插了两个 TB-RK1808 AI 计算棒,得到的结果如下:
adb_devices = []
ntb_devices = ['TB-RK1808S0', '515e9b401c060c0b']
from rknn.api import RKNN
if __name__ == '__main__':
rknn = RKNN()
rknn.list_devices()
rknn.release()
返回的设备列表信息如下(这里有两个 RK1808 开发板,它们的连接模式都是 adb):
*************************
all device(s) with adb mode:
['515e9b401c060c0b', 'XGOR2N4EZR']
*************************
查询模型可运行平台API: list_support_target_platform
查询给定 RKNN 模型可运行的芯片平台。
rknn_model:RKNN 模型路径。如果不指定模型路径,则按类别打印 RKNN-Toolkit当前支持的芯片平台。
support_target_platform: Returns runnable chip platforms, or None if the model path is empty.
rknn.list_support_target_platform(rknn_model=’mobilenet_v1.rknn’)
结果展示:
**************************************************
Target platforms filled in RKNN model: []
Target platforms supported by this RKNN model: ['RK1806', 'RK1808', 'RK3399PRO']
**************************************************