Win10上RKNN工具安装使用

Deceiver_Ker·2022-06-13 10:51·3956 次阅读

Win10上RKNN工具安装使用

1,配置基础Python环境为:

Python3.6

个人建议最好在Conda下新建一个虚拟环境进行安装。

2,在虚拟环境下使用以下命令新建一个RKNN环境,如下:

Copy
conda create --name=rknn python=3.6.8

3,执行以下命令进入虚拟环境:

Copy
conda activate rknn

进入虚拟环境后,再执行以下命令安装深度学习框架,如Tensorflow,Pytorch,Keras等。

Copy
pip install tensorflow==1.14.0
Copy
pip install torch==1.6.0+cpu torchvision==0.7.0+cpu -f https://download.pytorch.org/whl/torch_stable.html --user
Copy
pip install mxnet==1.5.0
Copy
pip install opencv-python
Copy
pip install gluoncv

之后,手动安装 lmdb,该 wheel 包放在 SDK/external/rknn-toolkit/packages/required-packages-for-win-python36 目录下。

推荐将该安装包复制出来放入Anaconda的pkg目录下。之后进入此pkg目录下执行以下命令进行安装,如下所示:

Copy
pip install lmdb-0.95-cp36-cp36m-win_amd64.whl

同理,复制出rknn安装包rknn_toolkit-1.6.0-cp36-cp36m-win_amd64.whl,位置在SDK/external/rknn-toolkit/packages/下,执行以下命令进行安装。

Copy
pip install rknn_toolkit-1.6.0-cp36-cp36m-win_amd64.whl

4,检测rknn是否安装成功,输入以下命令:

Copy
python
Copy
from rknn.api import RKNN

若无报错则安装RKNN成功

5,案例使用,模型转换:

本人使用的模型出自以下:https://github.com/bubbliiiing/mobilenet-ssd-keras/releases/download/v1.0/mobilenet_ssd_weights.h5 权重进一步训练生成的模型。训练环境为tf1.13+keras2.1.5

注意,在保存权重时需要将网络与权重参数一起保存,在保存函数中将save_weights_only设置为False即可,如下所示。

后面首先需要对于Keras训练出的H5权重进行转换生成pb文件,代码如下:

Copy
from nets.ssd_training import MultiboxLoss, get_lr_scheduler from keras.models import load_model import tensorflow as tf import os from keras import backend as K from tensorflow.python.framework import graph_util, graph_io from tensorflow.python.platform import gfile #h5topb def h5_to_pb(h5_weight_path, output_dir, out_prefix="output_", log_tensorboard=True): if not os.path.exists(output_dir): os.mkdir(output_dir) h5_model = load_model(h5_weight_path,custom_objects={'compute_loss':MultiboxLoss(num_classes=9, neg_pos_ratio=3.0).compute_loss}) out_nodes = [] for i in range(len(h5_model.outputs)): out_nodes.append(out_prefix + str(i + 1)) tf.identity(h5_model.output[i], out_prefix + str(i + 1)) model_name = os.path.splitext(os.path.split(h5_weight_path)[-1])[0] + '.pb' sess = K.get_session() init_graph = sess.graph.as_graph_def() main_graph = graph_util.convert_variables_to_constants(sess, init_graph, out_nodes) graph_io.write_graph(main_graph, output_dir, name=model_name, as_text=False) # 读取模型各层 def read_pb(GRAPH_PB_PATH): with tf.Session() as sess: print("load graph!!!") with gfile.FastGFile(GRAPH_PB_PATH, 'rb') as f: graph_def = tf.GraphDef() graph_def.ParseFromString(f.read()) tf.import_graph_def(graph_def, name='') for i, n in enumerate(graph_def.node): print("Name of the node - %s" % n.name) h5_to_pb(h5_weight_path='./testrknn.h5', output_dir='./') read_pb('./testrknn.pb')

在终端中将打印生成的pb文件模型的各个节点的名称,部分如下所示,非常重要,在模型转换时需要用到。

之后进入rknn的虚拟环境,输入以下指令进入可视化转换界面,如下所示::

Copy
python -m rknn.bin.visualization

这里由于转换的是pb文件,因此选择中间TensorFlow。

进入后相关配置如下:

之后Next进行下一个界面:

这里InPut Nodes与output Nodes的填写非常重要,填写错误之后模型转换会报错如下:

Copy
AttributeError: 'NoneType' object has no attribute 'XXXXXX'

一般这种错误是输入与输出节点错误填写导致的。

对于输入输出节点的的确认,不能将该文件中的输入、输出节点,简单的理解为模型(.pb)文件节点分析后的第一个和最后一个节点,因为对于RK平台来说,模型的前处理(preprocessor)和后处理(postprocessor)部分不直接利用平台NPU计算,会影响速度,而是使用DSP来处理,对于模型中间部分的大量卷积操作使用NPU。

填写完毕后Next将量化PB文件。

一路Next后,最终将生成RKNN文件,文件模型部分结构如下所示:

对于生成的rknn模型进行推理,测试性能,步骤如下所示(在Window上需要实物开发板进行推理,因此此步在Linux下以PC模型进行),测试代码如下:

Copy
import numpy as np import re import math import random import cv2 from rknn.api import RKNN INPUT_SIZE = 300 if __name__ == '__main__': # Create RKNN object rknn = RKNN() # Direct Load RKNN Model ret = rknn.load_rknn('./test.rknn') if ret != 0: print('Load model failed') exit(ret) print('done') # Set inputs orig_img = cv2.imread('./1.jpg') 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') # Evaluate Perf on Simulator rknn.eval_perf(inputs=[img], is_print=True) # Release RKNN Context rknn.release()

推理结果如下:

同时也可以用代码的方式编译转换与测试文件,转换与测试代码如下:

Copy
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 = 9 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() # Config for Model Input PreProcess #rknn.config(mean_values=[[127.5, 127.5, 127.5]], std_values=[[127.5, 127.5, 127.5]], reorder_channel='0 1 2') # Load TensorFlow Model #print('--> Loading model') #rknn.load_tensorflow(tf_pb='./ghostnet_ssd.pb', #inputs=['FeatureExtractor/MobilenetV1/MobilenetV1/Conv2d_0/Conv2D'], #outputs=['concat', 'concat_1'], #input_size_list=[[INPUT_SIZE, INPUT_SIZE, 3]]) #print('done') # Build Model #print('--> Building model') #rknn.build(do_quantization=True, dataset='./dataset.txt') #print('done') # Export RKNN Model #rknn.export_rknn('./ghostnet_ssd.rknn') # Direct Load RKNN Model rknn.load_rknn('./ghostnet_ssd.rknn') # Set inputs orig_img = cv2.imread('./test7.jpg') 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)) outputClasses = outputs[1].reshape((1, NUM_RESULTS, NUM_CLASSES)) candidateBox = np.zeros([2, NUM_RESULTS], dtype=int) 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 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" % (topClassScoreIndex, xmin, ymin, xmax, ymax, topClassScore)) cv2.rectangle(orig_img, (int(xmin), int(ymin)), (int(xmax), int(ymax)), (random.random()*255, random.random()*255, random.random()*255), 3) cv2.imwrite("out7.jpg", orig_img) # Evaluate Perf on Simulator rknn.eval_perf(inputs=[img], is_print=True) # Release RKNN Context rknn.release()

注意,代码中的box_priors与SSD模型中先验框有关,需要匹配自己的模型生成,生成代码如下:

Copy
import numpy as np class AnchorBox(): def __init__(self, input_shape, min_size, max_size=None, aspect_ratios=None, flip=True): self.input_shape = input_shape self.min_size = min_size self.max_size = max_size self.aspect_ratios = [] for ar in aspect_ratios: self.aspect_ratios.append(ar) self.aspect_ratios.append(1.0 / ar) def call(self, layer_shape, mask=None): # --------------------------------- # # 获取输入进来的特征层的宽和高 # 比如38x38 # --------------------------------- # layer_height = layer_shape[0] layer_width = layer_shape[1] # --------------------------------- # # 获取输入进来的图片的宽和高 # 比如300x300 # --------------------------------- # img_height = self.input_shape[0] img_width = self.input_shape[1] box_widths = [] box_heights = [] # --------------------------------- # # self.aspect_ratios一般有两个值 # [1, 1, 2, 1/2] # [1, 1, 2, 1/2, 3, 1/3] # --------------------------------- # for ar in self.aspect_ratios: # 首先添加一个较小的正方形 if ar == 1 and len(box_widths) == 0: box_widths.append(self.min_size) box_heights.append(self.min_size) # 然后添加一个较大的正方形 elif ar == 1 and len(box_widths) > 0: box_widths.append(np.sqrt(self.min_size * self.max_size)) box_heights.append(np.sqrt(self.min_size * self.max_size)) # 然后添加长方形 elif ar != 1: box_widths.append(self.min_size * np.sqrt(ar)) box_heights.append(self.min_size / np.sqrt(ar)) # --------------------------------- # # 获得所有先验框的宽高1/2 # --------------------------------- # box_widths = 0.5 * np.array(box_widths) box_heights = 0.5 * np.array(box_heights) # --------------------------------- # # 每一个特征层对应的步长 # --------------------------------- # step_x = img_width / layer_width step_y = img_height / layer_height # --------------------------------- # # 生成网格中心 # --------------------------------- # linx = np.linspace(0.5 * step_x, img_width - 0.5 * step_x, layer_width) liny = np.linspace(0.5 * step_y, img_height - 0.5 * step_y, layer_height) centers_x, centers_y = np.meshgrid(linx, liny) centers_x = centers_x.reshape(-1, 1) centers_y = centers_y.reshape(-1, 1) # 每一个先验框需要两个(centers_x, centers_y),前一个用来计算左上角,后一个计算右下角 num_anchors_ = len(self.aspect_ratios) anchor_boxes = np.concatenate((centers_x, centers_y), axis=1) anchor_boxes = np.tile(anchor_boxes, (1, 2 * num_anchors_)) # 获得先验框的左上角和右下角 anchor_boxes[:, ::4] -= box_widths anchor_boxes[:, 1::4] -= box_heights anchor_boxes[:, 2::4] += box_widths anchor_boxes[:, 3::4] += box_heights # --------------------------------- # # 将先验框变成小数的形式 # 归一化 # --------------------------------- # anchor_boxes[:, ::2] /= img_width anchor_boxes[:, 1::2] /= img_height anchor_boxes = anchor_boxes.reshape(-1, 4) anchor_boxes = np.minimum(np.maximum(anchor_boxes, 0.0), 1.0) return anchor_boxes #---------------------------------------------------# # 用于计算共享特征层的大小 #---------------------------------------------------# def get_img_output_length(height, width): filter_sizes = [3, 3, 3, 3, 3, 3, 3, 3] padding = [1, 1, 1, 1, 1, 1, 0, 0] stride = [2, 2, 2, 2, 2, 2, 1, 1] feature_heights = [] feature_widths = [] for i in range(len(filter_sizes)): height = (height + 2*padding[i] - filter_sizes[i]) // stride[i] + 1 width = (width + 2*padding[i] - filter_sizes[i]) // stride[i] + 1 feature_heights.append(height) feature_widths.append(width) return np.array(feature_heights)[-6:], np.array(feature_widths)[-6:] def get_anchors(input_shape = [300, 300], anchors_size = [30, 60, 111, 162, 213, 264, 315]): feature_heights, feature_widths = get_img_output_length(input_shape[0], input_shape[1]) aspect_ratios = [[1, 2], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2], [1, 2]] anchors = [] #print(feature_heights, feature_widths) for i in range(len(feature_heights)): anchors.append(AnchorBox(input_shape, anchors_size[i], max_size = anchors_size[i+1], aspect_ratios = aspect_ratios[i]).call([feature_heights[i], feature_widths[i]])) anchors = np.concatenate(anchors, axis=0) print(np.shape(anchors)) return anchors if __name__ == "__main__": tmp = get_anchors() temp = tmp.flatten() temp_box_x = [] temp_box_y = [] temp_box_w = [] temp_box_h = [] temp_box = [] #依次获取先验框中心x坐标 先验框中心y坐标 先验框宽 先验框高四个值 for i in range(0,np.shape(get_anchors())[0]*np.shape(get_anchors())[1],4): cx = (temp[i]+temp[i+2])/2 cy = (temp[i+1] + temp[i+3])/2 w = temp[i+2] - temp[i] h = temp[i+3] - temp[i+1] temp_box_y += [cy] temp_box_x += [cx] temp_box_h += [h] temp_box_w += [w] temp_box = np.concatenate([temp_box_y ,temp_box_x ,temp_box_h,temp_box_w], axis=0) np.savetxt('./box_priors_test.txt',temp_box, fmt='%0.8f')

补充说明:h5模型转换过程中遇到的一个错误,解决方法如下:

或者用以下代码:

Copy
def relu6(x): return K.relu(x, max_value=6)

并在加载H5文件时中,在其中的custom_objects中加入relu6,如以下形式。

Copy
load_model(h5_weight_path,custom_objects={'relu6':relu6})

参考博客:

https://blog.csdn.net/weixin_39289876/article/details/116064327

https://blog.csdn.net/weixin_39289876/article/details/116062202

https://blog.csdn.net/qq_43348528/article/details/122998830

posted @   Deceiver_Ker  阅读(3956)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示