在第五章中,使用官方的原版历程初步摸索了一下npu相关的测试方法,本章就开始介绍如何使用自己的模型并迁移到yy3568上面。在这个过程中,我选择的并不是自己训练模型,而是从 tensorflow 官网上下载预训练好的模型,进行迁移测试。在这个过程中,碰到了一些问题,主要集中在:
如何使用 rknn-toolkit2 对 tensorflow 官网上面训练好的模型https://tfhub.dev/google/imagenet/mobilenet_v2_035_224/classification/5magenetlabels.txt 进行转换rknn-toolkit2转换后为什么和在原始的模型测试的不一致?1. 使用 rknn-toolkit2 对 tensorflow 官网上面训练好的模型进行转换在这一部分中,主要解决的是第一个问题,在这个过程中主要是解决 python 软件包的依赖关系。过程如下:
因为我下载的是压缩包文件,解压之后如下所示:
▸ tree imagenet_mobilenet_v2_035_224_classification_5imagenet_mobilenet_v2_035_224_classification_5├── saved_model.pb└── variables ├── variables.data-00000-of-00001 └── variables.index2 directories, 3 files可以看到是 pb 类型的文件,如何引用这个文件我使用的 tensorflow-hub ,这个过程还算顺利,但是后续使用 rknn-toolkit2 对这个模型进行转换时就犯难了,因为在这个过程需要使用到 pb 文件是数据类型的,而从 tensorflow 官网下载的是pdp-11 pure executable not stripped - version 5类型的,就需要对这个类型进行转换,这里就是重点了,我尝试使用 python3.8 发现一致无法转换,提示错误,主要原因是部分功能不支持,但是我可以用 python3.10 对这个 pb 文件进行转换为 rknn 需要的 pb 文件,接下去就是安装 rknn 在 python3.10 上的依赖了,因为我发现上游的 rknn-toolkit2 已经支持 python3.10 了不过是在 ubuntu 上,我就尝试在 solus 上进行安装,通过将简单的依赖问题解决后,卡在了这里报错:
但是文件 requirements_cp310-1.5.0.txt 明确写的是这个版本的依赖,我去 pip 上查看这个软件包,是这样子的:
可以看到,明确写的只支持到 python3.7,最后我尝试到上游查看这个软件包的仓库,发现最新的提交已经支持到 python3.10 了:
然后,我就手动修改这个包的 setup.py 文件,补丁如下:
diff --git a/tensorflow_estimator/tools/pip_package/setup.py b/tensorflow_estimator/tools/pip_package/setup.pyindex 2568d6a..862cd6b 100644--- a/tensorflow_estimator/tools/pip_package/setup.py+++ b/tensorflow_estimator/tools/pip_package/setup.py@@ -30,14 +30,14 @@ doclines = __doc__.split('n') # this version string is semver compatible, but incompatible with pip. # for pip, we will remove all '-' characters from this string, and use the # result for pip.-_version = '2.8.0'+_version = '2.8.0.dev2021122109' required_packages = [ # we depend on tensorflow's declared pip dependencies. # add a new dep there if one is needed. ] -project_name = 'tensorflow_estimator'+project_name = 'tf-estimator-nightly' if '--project_name' in sys.argv: project_name_idx = sys.argv.index('--project_name') project_name = sys.argv[project_name_idx + 1]最重要的一个步骤是编译,这里就不能使用setup.py sdist这样的,需要参看仓库的 readme,根据描述打包软件包,具体指令是:
bazel build //tensorflow_estimator/tools/pip_package:build_pip_packagebazel-bin/tensorflow_estimator/tools/pip_package/build_pip_package /tmp/estimator_pip会在 /tmp 目录下打出 wheel 包,进行安装就可以了。安装好所有依赖的软件包后,使用 python3.10 安装 rknn_toolkit2-1.5.0+1fa95b5c-cp310-cp310-linux_x86_64.whl 就可以了。
▸ python3.10 -m pip install dist/tensorflow_estimator-2.8.0-py3-none-any.whldefaulting to user installation because normal site-packages is not writeablelooking in indexes: https://pypi.tuna.tsinghua.edu.cn/simpleprocessing ./dist/tensorflow_estimator-2.8.0-py3-none-any.whlinstalling collected packages: tensorflow-estimatorsuccessfully installed tensorflow-estimator-2.8.0接着就可以愉快地进行 pb 格式转换了,我使用的代码如下:
#!/usr/bin/python3.10label_path='./imagenetlabels.txt'model_path='./imagenet_mobilenet_v2_035_224_classification_5'check_src='./goldfish_299x299.jpg'import tensorflow as tfimport tensorflow_hub as hubimport numpy as npimport sysfrom tensorflow.python.framework import convert_to_constants as _convert_to_constantsdef h5_to_pb(h5_save_path): model = tf.keras.models.load_model(h5_save_path, compile=false) model.summary() full_model = tf.function(lambda input: model(input)) full_model = full_model.get_concrete_function(tf.tensorspec(model.inputs[0].shape, model.inputs[0].dtype)) # get frozen concretefunction frozen_func = _convert_to_constants.convert_variables_to_constants_v2(full_model) frozen_func.graph.as_graph_def() layers = [op.name for op in frozen_func.graph.get_operations()] print(- * 50) print(frozen model layers: ) for layer in layers: print(layer) print(- * 50) print(frozen model inputs: ) print(frozen_func.inputs) print(frozen model outputs: ) print(frozen_func.outputs) # save frozen graph from frozen concretefunction to hard drive tf.io.write_graph(graph_or_graph_def=frozen_func.graph, logdir=./frozen_models2, name=model.pb, as_text=false) print(save mode with write_graph success)def load_label_file(path): f = open(path, 'r') txt = [] for line in f.readlines(): curline=line.strip('n') txt.append(curline) #print(txt) return txtlabel_list = load_label_file(label_path)def load_and_format_img(path): image = tf.io.read_file(path) image = tf.image.decode_jpeg(image, channels=3) image = tf.image.resize(image, [224, 224]) image /= 255.0 image_list = np.array(list(image)) image_list = image_list.reshape(1, 224, 224, 3) return image_listmodel_obj = hub.load(model_path)model = tf.keras.sequential([hub.keraslayer(model_obj)])model.build([none, 224, 224, 3])if len(sys.argv) > 1: check_src = sys.argv[1]image4check = load_and_format_img(check_src)#print(image4check)tf.saved_model.save(model, imgnet.tf)model.save(imgnet3.tf)ans=model.predict(image4check, verbose=2)print(--------------------------------begin--)print(np.argmax(ans))print(label_list[np.argmax(ans)])print(--------------------------------end--)h5_to_pb(imgnet3.tf)可以看到,我在这里将从网上下载的模型 imagenet_mobilenet_v2_035_224_classification_5 转换为了 ./frozen_models2/model.pb 文件,测试结果如下所示:
省略 ...--------------------------------begin--2goldfish--------------------------------end--省略 ...至此, rknn-toolkit2 可以使用的 tensorflow 的 pb 文件已经有了,下一步是迁移到 yy3568 上进行测试了。我参考的是文件 rknn-toolkit2/examples/tensorflow/inception_v3_qat/test.py。进行修改后,最终内容如下:
#!/usr/bin/python3.10import numpy as npimport cv2import osimport urllibimport tarfileimport shutilimport tracebackimport timeimport sysfrom rknn.api import rknn#pb_file = './imgnet.tf/saved_model.pb'pb_file = './frozen_models2/model.pb'rknn_model_path = './red_imagenet_mobilenet_v2_035_224_classification_5.rknn'inputs = ['input']outputs = ['identity']img_path = './goldfish_224x224.jpg'#img_path = './german-shepherd_224x224.jpg'#img_path = '/var/lib/nfs/yy3568/red_own_model/cat_224x224.jpg'input_size = 224def show_outputs(outputs): output = outputs[0][0] output_sorted = sorted(output, reverse=true) top5_str = 'red imagenetn-----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.0n' top5_str += topi print(top5_str)def readable_speed(speed): speed_bytes = float(speed) speed_kbytes = speed_bytes / 1024 if speed_kbytes > 1024: speed_mbytes = speed_kbytes / 1024 if speed_mbytes > 1024: speed_gbytes = speed_mbytes / 1024 return {:.2f} gb/s.format(speed_gbytes) else: return {:.2f} mb/s.format(speed_mbytes) else: return {:.2f} kb/s.format(speed_kbytes)def show_progress(blocknum, blocksize, totalsize): speed = (blocknum * blocksize) / (time.time() - start_time) speed_str = speed: {}.format(readable_speed(speed)) recv_size = blocknum * blocksize f = sys.stdout progress = (recv_size / totalsize) progress_str = {:.2f}%.format(progress * 100) n = round(progress * 50) s = ('#' * n).ljust(50, '-') f.write(progress_str.ljust(8, ' ') + '[' + s + ']' + speed_str) f.flush() f.write('rn')if __name__ == '__main__': # create rknn object rknn = rknn(verbose=true) # if inception_v3_quant_frozen.pb does not exist, download it. # download address: # https://storage.googleapis.com/download.tensorflow.org/models/tflite_11_05_08/inception_v3_quant.tgz if not os.path.exists(pb_file): print('oh no exist file ', pb_file) exit # pre-process config print('-- > config model') # 这里很重要,如果照抄 inception_v3_quant 的均值和标准值会导致分类有很大误差!!! rknn.config(mean_values=[0, 0, 0], std_values=[255, 255, 255], target_platform='rk3568') print('done') # load model print('-- > loading model') ret = rknn.load_tensorflow(tf_pb=pb_file, inputs=inputs, outputs=outputs, 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='./red_quantization.txt') if ret != 0: print('build model failed!') exit(ret) print('done') # export rknn model print('-- > export rknn model') ret = rknn.export_rknn(rknn_model_path) if ret != 0: print('export rknn model failed!') exit(ret) print('done') # set inputs img = cv2.imread(img_path) img = cv2.cvtcolor(img, cv2.color_bgr2rgb) # 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]) np.save('./tensorflow_inception_v3_qat_0.npy', outputs[0]) x = outputs[0] output = np.exp(x)/np.sum(np.exp(x)) outputs = [output] show_outputs(outputs) print('done') rknn.release()使用上述脚本进行测试,同样是 goldfish 的图片,结果如下:
省略 ...red imagenet-----top 5-----[2]: 0.9564507007598877[122]: 0.007486562244594097[121]: 0.005268004257231951[964]: 0.0018354274798184633[119]: 0.0017108423635363579done可以看到也准确地识别出了 goldfish 的编号 2。
从图中可以看到仿真模拟结果显示的 top5 内容,后续可以和在yy3568上实际运行的结果进行对比。
2. rknn-toolkit2转换后为什么和在原始的模型测试的不一致?针对 rknn-toolkit2转换后为什么和在原始的模型测试的不一致?的问题,在上述代码中,我已经添加了注释,关键的处理在:rknn.config(mean_values=[0, 0, 0], std_values=[255, 255, 255]) 这里,其中 meas_value 表示对应的均值, std_values 表示对应的标准值。看下文档的描述会更清晰:
开始我照抄例程的这两个参数导致 pc 原始模型的结果和 rknn-toolkit2 转换之后的结果有很大误差。这里解决了之后就是简单在 yy3568 上使用 npu 实际验证了。因为到目前位置,我们已经有了 xxxx.rknn 的模型文件,也有需要分类的图片,缺少一个在 yy3568 上运行的可执行程序,我使用的可执行程序是工程 external/rknpu2/examples/rknn_common_test。编译出来后,使用 nfs 挂载,在 yy3568 上测试,测试结果如下:
[root@rk356x:/media/red_nfs/yy3568/red_own_model/rknn_common_test_linux]# ./rknn_common_test ../red_imagenet_mobilenet_v2_035_224_classification_5_right.rknn ../goldfish_224x224.jpgrknn_api/rknnrt version: 1.3.0 (9b36d4d74@2022-05-04t20:17:01), driver version: 0.7.2model input num: 1, output num: 1input tensors: index=0, name=input:0, n_dims=4, dims=[1, 224, 224, 3], n_elems=150528, size=150528, fmt=nhwc, type=int8, qnt_type=affine, zp=-128, scale=0.003922output tensors: index=0, name=identity:0, n_dims=2, dims=[1, 1001, 0, 0], n_elems=1001, size=1001, fmt=undefined, type=int8, qnt_type=affine, zp=-66, scale=0.070292custom string:begin perf ... 0: elapse time = 3.36ms, fps = 297.53---- top5 ----11.738696 - 27.029160 - 1226.958868 - 1215.693619 - 1195.553036 - 964可以看到也准确识别出来了类型编号为2。支持完成了自定义模型的测试以及迁移。
四款折叠屏手机对比 谁才是目前最可用的手机
详解Celerity光纤通道卡的独特优势
全面屏大行其道 三星Galaxy S8或采用弃Home实体键
TD-SCDMA小区初搜方法研究
日间行车灯和雾灯的区别在哪里
【风火轮YY3568开发板免费体验】第六章:在Solus上运行自定义模型并迁移到YY3568对比测试
5G技术实现电子设备制造行业数字化转型的有益探索
海外专家回国合作研发“芯片” 公司买地建完一栋楼就没钱了
国网联研院将以三型两网推动世界一流能源互联网企业建设
努比亚Z11黑科技揭晓,女神专机!
华为p10与华为p9全方位对比?你选择谁?
OTDR的技术参数及在光纤检测中的测试方法与应用
电信运营商们努力推动Open RAN技术发展,呼吁在竞争同时也要团结
旺宏电子推出全球首颗256Mbit序列快闪存储器
三相异步电动机效率低的原因是什么
江苏大丰高新区获总投资约20亿元的锂电池项目,预计年底正式投产
面向可穿戴设备市场,这款无线供电新产品优势凸显!
DW01A/DW01系列锂电池保护芯片
基础网和业务网同步演进 中国联通构建新一代光传送网
5款主流充电宝充电实测 谁的充电效率最高