被低估的ArmNN(二)用C++部署Mobilenet回归器

在专栏之前的文章,我们介绍过armnn,详情可参考被低估的armnn(一)如何编译。这里,我们给大家介绍如何使用armnn在android设备上进行部署,部署的任务以mobilenet分类器为例。关于mobilenet回归器的训练,大家可以参考如何diy轻型的mobilenet回归器。我们今天的部署平台仍然是基于rk3399嵌入式平台,系统为android-8.1。
作者:张新栋 我们知道armnn是一个非常高效的inference框架,300x300的mobilenet-ssd在depth_multiplier取1.0时inference最快可达90ms/帧。今天我们将使用armnn框架,用c++在rk-3399-android-8.1中进行mobilenet回归任务的部署。首先我们先进行第一步,环境的配置。
环境配置 若想使用编译好的armnn进行inference,首先我们必须要先加载编译好的armnn库、头文件及其他依赖文件。这里我们依旧为大家提供了android.mk及application.mk,
local_path := $(call my-dir)include $(clear_vars)local_module := armnnlocal_src_files := $(local_path)/../libarmnn.solocal_export_c_includes := $(local_path)/../../include/armnnlocal_shared_libraries := c++_sharedinclude $(prebuilt_shared_library)include $(clear_vars)local_module := tfliteparserlocal_src_files := $(local_path)/../libarmnntfliteparser.solocal_export_c_includes := $(local_path)/../../include/libarmnntfliteparserlocal_shared_libraries := c++_sharedinclude $(prebuilt_shared_library)include $(clear_vars)local_module := armnnserializerlocal_src_files := $(local_path)/../libarmnnserializer.solocal_export_c_includes := $(local_path)/../../include/armnn/armnnserializerlocal_shared_libraries := c++_sharedinclude $(prebuilt_shared_library)include $(clear_vars)opencv_install_modules := onopencv_lib_type := staticinclude /users/xindongzhang/armnn-tflite/opencv-android-sdk/sdk/native/jni/opencv.mklocal_module := face_detectorlocal_c_includes += $(opencv_include_dir)local_c_includes += $(local_path)/../../includelocal_c_includes += $(local_path)/../../../boost_1_64_0/local_c_includes += $(local_path)/../../third-party/stb/local_src_files := / face_detector.cpplocal_ldlibs := -landroid -llog -ldl -lz local_cflags := -o2 -fvisibility=hidden -fomit-frame-pointer -fstrict-aliasing / -ffunction-sections -fdata-sections -ffast-math -ftree-vectorize / -fpic -ofast -ffast-math -w -std=c++14local_cppflags := -o2 -fvisibility=hidden -fvisibility-inlines-hidden -fomit-frame-pointer / -fstrict-aliasing -ffunction-sections -fdata-sections -ffast-math -fpic / -ofast -ffast-math -std=c++14local_ldflags += -wl,--gc-sectionslocal_cflags += -fopenmplocal_cppflags += -fopenmplocal_ldflags += -fopenmplocal_arm_neon := trueapp_allow_missing_deps = truelocal_shared_libraries := / armnn / tfliteparser / armnnserializer / android.hardware.neuralnetworks@1.0 / android.hidl.allocator@1.0 / android.hidl.memory@1.0 / libc++_sharedinclude $(build_executable) 如下为application.mk文件,
android_toolchain=clang app_abi := arm64-v8aapp_cppflags := -frtti -fexceptions -std=c++14app_platform := android-27app_stl := c++_shared 这里需要注意的是application.mk的app_stl项,由于我们在编译armnn时使用的stl为c++_shared,所以这里需要使用c++_shared,另外android.mk文件中链接的opencv库也需要使用c++_shared的stl进行编译(官网下载的即c++_shared编译)。
编写c++业务代码 在配置好依赖项后,我们开始使用armnn提供的c++api进行业务代码的书写。首先第一步我们需要加载模型,armnn提供了解析题 itfliteparserptr,我们可以使用其进行模型的加载。另外加载好的模型我们需要使用一个网络结构进行存储,armnn提供了inetworkptr。为了在对应的arm嵌入式平台中高效的执行,armnn还提供了ioptimizednetworkptr来对网络的inference进行优化。更多的细节大家可参考如下的业务代码。
armnntfliteparser::itfliteparserptr parser = armnntfliteparser::itfliteparser::create(); armnn::inetworkptr pose_reg_network{nullptr, [](armnn::inetwork *){}};armnn::ioptimizednetworkptr pose_reg_optnet{nullptr, [](armnn::ioptimizednetwork *){}};armnn::inputtensors pose_reg_in_tensors;armnn::outputtensors pose_reg_ou_tensors;armnn::iruntimeptr runtime{nullptr, [](armnn::iruntime *){}};float yaw[1];float pose_reg_input[64*64*3];// loading tflite modelstd::string pose_reg_modelpath = /sdcard/algo/pose.tflite;pose_reg_network = parser->createnetworkfrombinaryfile(pose_reg_modelpath.c_str());// binding input and outputarmnntfliteparser::bindingpointinfo pose_reg_input_bind = parser->getnetworkinputbindinginfo(0, input/imageinput);armnntfliteparser::bindingpointinfo pose_reg_output_bind = parser->getnetworkoutputbindinginfo(0, yaw/yangle);// wrapping pose reg input and outputarmnn::tensor pose_reg_input_tensor(pose_reg_input_bind.second, pose_reg_input);pose_reg_in_tensors.push_back(std::make_pair(pose_reg_input_bind.first, pose_reg_input_tensor));armnn::tensor pose_reg_output_tensor(pose_reg_output_bind.second, yaw);pose_reg_ou_tensors.push_back(std::make_pair(pose_reg_output_bind.first, pose_reg_output_tensor));// config runtime, fp16 accuracy armnn::iruntime::creationoptions runtimeoptions;runtime = armnn::iruntime::create(runtimeoptions);armnn::optimizeroptions optimizeroptions;optimizeroptions.m_reducefp32tofp16 = true;this->pose_reg_optnet = armnn::optimize(*pose_reg_network, {armnn::compute::gpuacc},runtime->getdevicespec(), optimizeroptions);runtime->loadnetwork(this->pose_reg_identifier, std::move(this->pose_reg_optnet));// load imagecv::mat rgb_image = cv::imread(face.jpg, 1);cv::resize(rgb_image, rgb_image, cv::size(pose_reg_input_size, pose_reg_input_size));rgb_image.convertto(rgb_image, cv_32fc3);rgb_image = (rgb_image - 127.5f) * 0.017f;// preprocess imageint total = 64 * 64 * 3;float* data = (float*) rgb_image.data;for (int i = 0; i enqueueworkload( this->pose_reg_identifier, this->pose_reg_in_tensors, this->pose_reg_ou_tensors);float result = yaw[0] * 180 / 3.14; 非常简单易懂的业务代码就可以完成armnn的一次inference,注意这里我们使用的是fp16来进行inference,相比于fp32,fp16具有更高的加速比,且不会损失很多精度。后续我们会给出如何使用armnn来做int8的inference例子。
最后 本文我们介绍了如何使用armnn来进行mobilenet的inference(其实很容易就可以改成分类任务),并使用fp16的精度进行inference,该网络在rk3399中执行效率非常高(约10ms)。若你想在其他设备中使用fp16,首先你要保证设备中有gpu,且支持opencl。欢迎大家留言讨论、关注专栏,谢谢大家!


是对手亦是队友 曝光小米宣传视频用的华为服务器
非蜂窝低功耗窄带物联网能否真正走向“共同富裕”?
为什么MOS管栅极串联电阻越小越好
中日韩信息通信部长会议:确定下一代高速通信网的实用化等进行合作
Type-c多口移动电源方案
被低估的ArmNN(二)用C++部署Mobilenet回归器
光纤通信利用什么传递信息_光纤通信的载体
干簧技术课堂-第四课
氟化工冷凝器管板与管束焊接口腐蚀渗漏保护,创新技术将设备维修带入崭新格局
iOS 11 恐怕是系统体验最糟糕的一个版本 今年更新的 iOS 12 可能也不会有特别大的变化
区块链和加密货币在娱乐业中的作用
iPhone8发布时间确定!iphone8真机操作图片曝光:取消Hone键的iPhone8请这样操作
防雷保护之风光互补发电系统的介绍
鹿客推出首款推拉形态智能门锁 安全性全方面升级
分享领好礼,再买现货丰富电赛或毕设资源!【拿回馈优惠码】
苹果发布全新3D地图 支持3D实景及语音导航
LDO(低压差线性稳压器)选型小结
关于自动摇窗机模块/后门控制模块的性能分析和应用
天啊,我是不是用了假的Office啊?为什么你用了这么多年却突然不认识Microsoft Office呢
LTC2380-24 ADC采样精确度分析报告