赞
踩
这次体验的硬件平台是来自飞凌嵌入式的OK3588-C开发板,该开发板基于Rockchip新一代旗舰 RK3588处理器开发,采用核心板+底板的分体式设计,将FET3588-C核心板的全部功能引脚以最便利的方式引出,并针对不同的功能做了深度优化,方便用户二次开发的同时简化用户设计。
rk3588专门针对机器学习模型部署的需求配置了性能强劲的NPU,rk3588配置的NPU不仅提供6TOPS的算力,还支持INT4/INT8/INT16/FP16格式的混合操作。除了非常不错的硬件支持之外,Rockchip公司还提供了便捷的开发工具rknn-toolkit2 和 rknpu2-api,让开发者可以方便的将自己的机器学习模型进行转换和部署。
根据rockchip提供的《Rockchip_User_Guide_RKNN_Toolkit2》开发文档介绍:
RKNN-Toolkit2 是为用户提供在 PC、Rockchip NPU 平台上进行模型转换、推理和性能评估的
开发套件,用户通过该工具提供的 Python 接口可以便捷地完成以下功能:
可以从github上的rockchip官方仓库中下载最新的适合于本地python环境的rknn_toolkit2安装文件,目前github上最新的版本已经支持python3.10了。下载完python安装文件后,可以用pip直接安装,这里以python3.10版本为例。需要注意的是rknn_toolkit2的安装是以来tensorflow2.8版本tf-estimator-nightly特定版本的。所以在安装rknn_toolkit2之前先利用pip安装tensorflow2.8版本,对于已经安装其他版本tensorflow的,要先进行卸载,再重新安装。
pip3 install tensorflow==2.8
pip3 install tf-estimator-nightly==2.8.0.dev2021122109 -i https://pypi.org/simple
接着用pip安装刚下在的rknn_toolkit2安装包。
pip3 install rknn_toolkit2-1.5.2%2Bb642f30c-cp310-cp310-linux_x86_64.whl
下图是安装完成后的提示信息:
在安装完成之后,可以直接使用rknn_toolkit2提供的demo程序进行测试。这里我们选择tensorflow构建的机器学习模型进行测试。
官方提供的测试程序在rknn-toolkit2/examples/tensorflow/ssd_mobilenet_v1路径下。
具体测试程序如下:
import numpy as np import re import math import random import cv2 from rknn.api import RKNN INPUT_SIZE = 300 NUM_RESULTS = 1917 NUM_CLASSES = 91 Y_SCALE = 10.0 X_SCALE = 10.0 H_SCALE = 5.0 W_SCALE = 5.0 def expit(x): return 1. / (1. + math.exp(-x)) def unexpit(y): return -1.0 * math.log((1.0 / y) - 1.0) def CalculateOverlap(xmin0, ymin0, xmax0, ymax0, xmin1, ymin1, xmax1, ymax1): w = max(0.0, min(xmax0, xmax1) - max(xmin0, xmin1)) h = max(0.0, min(ymax0, ymax1) - max(ymin0, ymin1)) i = w * h u = (xmax0 - xmin0) * (ymax0 - ymin0) + (xmax1 - xmin1) * (ymax1 - ymin1) - i if u <= 0.0: return 0.0 return i / u def load_box_priors(): box_priors_ = [] fp = open('./box_priors.txt', 'r') ls = fp.readlines() for s in ls: aList = re.findall('([-+]?\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?', s) for ss in aList: aNum = float((ss[0]+ss[2])) box_priors_.append(aNum) fp.close() box_priors = np.array(box_priors_) box_priors = box_priors.reshape(4, NUM_RESULTS) return box_priors if __name__ == '__main__': # Create RKNN object rknn = RKNN(verbose=True) # Pre-process config print('--> Config model') rknn.config(mean_values=[127.5, 127.5, 127.5], std_values=[127.5, 127.5, 127.5], target_platform='rk3566') print('done') # Load model (from https://github.com/fvmassoli/Deep-Learning-SSD-Object-Detection) print('--> Loading model') ret = rknn.load_tensorflow(tf_pb='./ssd_mobilenet_v1_coco_2017_11_17.pb', inputs=['Preprocessor/sub'], outputs=['concat', 'concat_1'], input_size_list=[[1, INPUT_SIZE, INPUT_SIZE, 3]]) if ret != 0: print('Load model failed!') exit(ret) print('done') # Build Model print('--> Building model') ret = rknn.build(do_quantization=True, dataset='./dataset.txt') if ret != 0: print('Build model failed!') exit(ret) print('done') # Export rknn model print('--> Export rknn model') ret = rknn.export_rknn('./ssd_mobilenet_v1_coco.rknn') if ret != 0: print('Export rknn model failed!') exit(ret) print('done') # Set inputs orig_img = cv2.imread('./road.bmp') img = cv2.cvtColor(orig_img, cv2.COLOR_BGR2RGB) img = cv2.resize(img, (INPUT_SIZE, INPUT_SIZE), interpolation=cv2.INTER_CUBIC) # Init runtime environment print('--> Init runtime environment') ret = rknn.init_runtime() if ret != 0: print('Init runtime environment failed!') exit(ret) print('done') # Inference print('--> Running model') outputs = rknn.inference(inputs=[img]) print('done') predictions = outputs[0].reshape((1, NUM_RESULTS, 4)) np.save('./tensorflow_ssd_mobilenet_v1_0.npy', outputs[0]) outputClasses = outputs[1].reshape((1, NUM_RESULTS, NUM_CLASSES)) np.save('./tensorflow_ssd_mobilenet_v1_1.npy', outputs[0]) candidateBox = np.zeros([2, NUM_RESULTS], dtype=int) classScore = [-1000.0] * NUM_RESULTS vaildCnt = 0 box_priors = load_box_priors() # Post Process # got valid candidate box for i in range(0, NUM_RESULTS): topClassScore = -1000 topClassScoreIndex = -1 # Skip the first catch-all class. for j in range(1, NUM_CLASSES): score = expit(outputClasses[0][i][j]) if score > topClassScore: topClassScoreIndex = j topClassScore = score if topClassScore > 0.4: candidateBox[0][vaildCnt] = i candidateBox[1][vaildCnt] = topClassScoreIndex classScore[vaildCnt] = topClassScore vaildCnt += 1 # calc position for i in range(0, vaildCnt): if candidateBox[0][i] == -1: continue n = candidateBox[0][i] ycenter = predictions[0][n][0] / Y_SCALE * box_priors[2][n] + box_priors[0][n] xcenter = predictions[0][n][1] / X_SCALE * box_priors[3][n] + box_priors[1][n] h = math.exp(predictions[0][n][2] / H_SCALE) * box_priors[2][n] w = math.exp(predictions[0][n][3] / W_SCALE) * box_priors[3][n] ymin = ycenter - h / 2. xmin = xcenter - w / 2. ymax = ycenter + h / 2. xmax = xcenter + w / 2. predictions[0][n][0] = ymin predictions[0][n][1] = xmin predictions[0][n][2] = ymax predictions[0][n][3] = xmax # NMS for i in range(0, vaildCnt): if candidateBox[0][i] == -1: continue n = candidateBox[0][i] xmin0 = predictions[0][n][1] ymin0 = predictions[0][n][0] xmax0 = predictions[0][n][3] ymax0 = predictions[0][n][2] for j in range(i+1, vaildCnt): m = candidateBox[0][j] if m == -1: continue xmin1 = predictions[0][m][1] ymin1 = predictions[0][m][0] xmax1 = predictions[0][m][3] ymax1 = predictions[0][m][2] iou = CalculateOverlap(xmin0, ymin0, xmax0, ymax0, xmin1, ymin1, xmax1, ymax1) if iou >= 0.45: candidateBox[0][j] = -1 # Draw result for i in range(0, vaildCnt): if candidateBox[0][i] == -1: continue n = candidateBox[0][i] xmin = max(0.0, min(1.0, predictions[0][n][1])) * INPUT_SIZE ymin = max(0.0, min(1.0, predictions[0][n][0])) * INPUT_SIZE xmax = max(0.0, min(1.0, predictions[0][n][3])) * INPUT_SIZE ymax = max(0.0, min(1.0, predictions[0][n][2])) * INPUT_SIZE print("%d @ (%d, %d) (%d, %d) score=%f" % (candidateBox[1][i], xmin, ymin, xmax, ymax, classScore[i])) cv2.rectangle(orig_img, (int(xmin), int(ymin)), (int(xmax), int(ymax)), (random.random()*255, random.random()*255, random.random()*255), 3) cv2.imwrite("result.jpg", orig_img) rknn.release()
以上程序主要包括以下几个步骤和对应的接口(省略了参数调用):
以上是针对tensorflow框架下的机器学习模型的转换和运行步骤,rknn-toolkit2还支持以下机器学习模型框架:
机器学习模型框架 | 输入模型文件后缀 | 对应模型加载API |
---|---|---|
Caffe | .prototxt | load_caffe |
TensorFlow | .pb | load_tensorflow |
TensorFlow Lite | .tflite | load_tflite |
ONNX | .onnx | load_onnx |
DarkNet | .cfg | load_darknet |
PyTorch | .pt | load_pytorch |
rknn模型的推理运行有两种方式,一种是直接在PC上利用模拟环境调用rknn模型进行推理运算。还有一种是利用rk3588上的硬件NPU进行推理运算。第二种方式需要在PC和RK3588开发板之间进行数据传输,主要包括以下步骤:
/usr/bin/rknn_server start
rknn_server启动后会打印相关信息,并且在有PC端连接时也会打印相应信息,如下图所示:
rknn.init_runtime(target='rk3588')
python3 test.py
得到输出结果如下:
从上面的打印信息可以看出, PC上的rknn-toolkit2成功与开发板上运行的rknn服务器连接成功,并且通过调用rk3588的硬件NPU进行模型的推理运算,得出运算结果。
下图是通过连板运行模型推理得到的结果,可以看出目标检测模型成功检测出凸显各种的人,自行车,汽车等目标。
通过rknn-toolkit2开发工具,可以方便的将各种框架下得到的机器学习模型转化为rk3588需要的rknn模型,并且调用rk3588的NPU进行模型的推理运算。考虑到rk3588的NPU具有很强的运算能力(6TOPS),将机器学习模型部署到rk3588上并由专用的NPU提供算力支持,可以大大提高模型的计算速度和能力,为机器学习模型的终端部署提供有效保证。
当然,在实际产品开发中,如果是使用python环境,其实是通过在rk3588中调用rknn-lite工具包调用rknn模型进行推理计算。而更高效的方式则是利用rockchip公司提供的rknpu的C语言API对转换后的rknn模型进行调用和推理,关于这部分内容,有机会博主会在后续的文章中详细总结整理。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。