之前的文章中,我们跟大家介绍过如何使用NNAPI来加速TFLite-Android的inference(可参考使用NNAPI加速android-tflite的Mobilenet分类器)。不过之前介绍的文章,在进行模型加载和推断使用的是官方提供的预编译好的Jar文件,业务代码都通过Java进行编写。如果你想使用C++在native层进行业务代码的编写,你也可以参考本文的实现思路。跟之前专栏中介绍的框架一样,我们首先需要进行框架的编译 — TFLite的库函数编译。我们先下载最新版本master分支的tensorflow源码。

git clone https://github.com/tensorflow/tensorflow

在下载好源码以后,我需要进入tensorflow文件夹目录下,然后进行配置。在此之前,你还需要确保NDK和Bazel安装的正确性,本文采用的NDK为ndk-r17c,bazel采用的版本为 0.24.1。

cd tensorflow
./configure

配置完毕后,你还需要在该目录下的WORKSPACE文件中添加ndk的环境,直接在文件的末尾加入如下参数即可,

android_ndk_repository(name = "androidndk", # Required. Name *must* be "androidndk".api_level = 21,
)

本文在RK3288开发板进行验证,Android系统为5.1版本。所以为了兼容,这里采用的APP_PLATFORM为21,对应于api_level为21。下面,我们开始进行TFLite的模型编译。

bazel build -c opt --crosstool_top=//external:android/crosstool
--host_crosstool_top=@bazel_tools//tools/cpp:toolchain --cxxopt="-std=c++11"
--fat_apk_cpu=armeabi-v7a --config=android_arm
//tensorflow/lite:libtensorflowlite.so

这里面有几个参数需要注意,一个是--fat_apk_cpu和--config。在Android平台中一般fat_apk_cpu可取arm64-v8a或armeabi-v7a,config可选为android_arm64或android_arm。更详细的配置大家可参考/tensorflow/lite/build_def.bzl该文件。

编译好的模型libtensorflowlite.so会保存在/tensorflow/bazel-bin/tensorflow/lite文件夹中,下面我们开始配置依赖环境,进行C++业务代码的编写。配置环境大家可参考如下mk脚本,注意将环境变量替换成你本机的环境变量。需要注意的地方,引入tensorflow的头文件路径的同时,也需要引入flatbuffer的头文件路径

LOCAL_PATH := $(call my-dir)OpenCV_BASE = /Users/xindongzhang/armnn-tflite/OpenCV-android-sdk/
TFLITE_BASE = /Users/xindongzhang/Desktop/tflite-cpp/jni/tensorflow
FLATBUFFER_BASE = /Users/xindongzhang/armnn-tflite/flatbuffers/include $(CLEAR_VARS)
LOCAL_MODULE := TFLITE
LOCAL_SRC_FILES := $(TFLITE_BASE)/bazel-bin/tensorflow/lite/libtensorflowlite.so
include $(PREBUILT_SHARED_LIBRARY)include $(CLEAR_VARS)
OpenCV_INSTALL_MODULES := on
OPENCV_LIB_TYPE := STATIC
include $(OpenCV_BASE)/sdk/native/jni/OpenCV.mk
LOCAL_MODULE := tflite_ssdLOCAL_C_INCLUDES += $(OPENCV_INCLUDE_DIR)
LOCAL_C_INCLUDES += $(TFLITE_BASE)/tensorflow
LOCAL_C_INCLUDES += $(TFLITE_BASE)
LOCAL_C_INCLUDES += $(FLATBUFFER_BASE)/includeLOCAL_SRC_FILES :=                        main.cpp                  LOCAL_LDLIBS := -landroid -llog -ldl -lz -fuse-ld=gold
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++14
LOCAL_CPPFLAGS := -O2 -fvisibility=hidden -fvisibility-inlines-hidden
-fomit-frame-pointer -fstrict-aliasing -ffunction-sections -fdata-sections
-ffast-math -fPIC -Ofast -ffast-math -std=c++14
LOCAL_LDFLAGS  += -Wl,--gc-sections
LOCAL_CFLAGS   += -fopenmp
LOCAL_CPPFLAGS += -fopenmp
LOCAL_LDFLAGS  += -fopenmp
LOCAL_ARM_NEON := trueAPP_ALLOW_MISSING_DEPS = trueLOCAL_SHARED_LIBRARIES :=                             TFLITE             include $(BUILD_EXECUTABLE)

接下来是C++业务代码,跟在java中的调用逻辑是一样的,先加载模型,然后进行解析;输入数据时候要根据训练时的预处理方式,进行对等的预处理操作;最后执行inference,取出结果,如有后处理,再进行相应的后处理。

    std::string model_file = "./detect.tflite";std::string image_file = "./322353.jpg";int INPUT_SIZE = 300;cv::Mat raw_image = cv::imread(image_file, 1);cv::Mat image;  cv::resize(raw_image, image, cv::Size(INPUT_SIZE, INPUT_SIZE));image.convertTo(image, CV_32FC3);image = (image * 2.0f / 255.0f) - 1.0f;std::unique_ptr<tflite::FlatBufferModel> model;tflite::ops::builtin::BuiltinOpResolver resolver;std::unique_ptr<tflite::Interpreter> interpreter;TfLiteTensor* input_tensor     = nullptr;TfLiteTensor* output_locations = nullptr;TfLiteTensor* output_classes   = nullptr;TfLiteTensor* output_scores    = nullptr;TfLiteTensor* num_detections   = nullptr;model = tflite::FlatBufferModel::BuildFromFile(model_file.c_str());tflite::InterpreterBuilder(*model, resolver)(&interpreter);interpreter->AllocateTensors();input_tensor = interpreter->tensor(interpreter->inputs()[0]);interpreter->SetNumThreads(1);// preprocessingfloat* dst = input_tensor->data.f;const int row_elems = image.cols * image.channels();for (int row = 0; row < image.rows; row++) {const uchar* row_ptr = image.ptr(row);for (int i = 0; i < row_elems; i++) {dst[i] = row_ptr[i];}dst += row_elems;}// run inferenceinterpreter->Invoke();// get output output_locations = interpreter->tensor(interpreter->outputs()[0]);output_classes   = interpreter->tensor(interpreter->outputs()[1]);

  • 最后

在完成上述过程后,既可以在Android中使用C++进行TFlite模型的部署。目前TFLIte在嵌入式端的竞争力虽然不是很强,但是开发的活跃度依旧很高,推出了许多新的特性,如xla、int8、量化、fp16,以及配套的离线量化、压缩脚本,后续本专栏会持续关注TFlite在嵌入式端的进展。欢迎大家留言讨论、关注本专栏,谢谢大家。

实战嵌入端的AI算法​zhuanlan.zhihu.com

android ndk怎样加载o文件_在Android中使用TFLite c++部署相关推荐

  1. android ndk怎样加载o文件_JNI初探之NDK 开发环境配置

    安装 CMake.LLDB与NDK 开发工具包 CMake 简介 CMake 是一款比make更强大的编译自动配置工具,它可以根据不同平台.不同的编译器,并通过CMakeLists.txt文件中简单的 ...

  2. Android studio 使用心得(六)---android studio 如何加载.so文件

    2019独角兽企业重金招聘Python工程师标准>>> 之前一直没怎么注意,以为.so文件android为像eclipse一样直接加载,但是直到昨天我在android studio上 ...

  3. Android NDK动态加载SO库

    背景 对于一个普通的android应用来说,so库的占比通常都是巨高不下的,因为我们无可避免的在开发中遇到各种各样需要用到native的需求,所以so库的动态化可以减少极大的包体积,自从2020腾讯的 ...

  4. pyqt5从子目录加载qrc文件_【JVM系统学习之路】一篇看懂类加载

    JVM系统学习之路系列演示代码地址:https://github.com/mtcarpenter/JavaTutorial 嗨喽,小伙伴大家好,我是小春哥,今天是打卡 [JVM系统学习之路] 的第二篇 ...

  5. ccs加载out文件_类加载流程、类加载机制及自定义类加载器详解

    原文:juejin.im/post/5cffa528e51d4556da53d091 一.引言 当程序使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载.链接.初始化三个步骤对该类进行类加载 ...

  6. axios vue 加载效果动画_在vue中通过axios异步使用echarts

    现实的工作中, 数据不可能是像之前的demo演示的那样把数据写死的. 所有的数据都应该通过发送请求进行获取, 所以, 这篇文章, 我将在Vue项目中使用Echarts: 在Vue中引入Echarts中 ...

  7. android使用webview加载flash文件

    android 字段webview几乎实现了浏览器的全部功能,最近在使用webview加载不固定格式的文章,文章中有一部分嵌入了flash,下面就是webview可以进行视频需要进行的设置,代码如下: ...

  8. android webview拦截加载离线文件

    概述 客户端经常会通过使用webview来用H5实现一些ios与android双端都有的功能,最常见的比如一些活动页面,内部广告页面等. 这些页面大概会有以下几个特点: 要求webview快一些,白屏 ...

  9. cad无法加载arx文件_多年经验总结CAD技巧8

    72.[关于选择的问题] 当绘图时没有虚线框显示,比如画一个矩形,取一点后,拖动鼠标时没有矩形虚框跟着变化,这时需修改DRAGMODE的系统变量,推荐修改为AUTO. 系统变量为ON时,再选定要拖动的 ...

最新文章

  1. 在GridView内访问特定控件
  2. 【图像分割】图像分割专栏栏主自述:分割,我们究竟在研究什么?
  3. 【软考-软件设计师】程序设计语言基础知识框架
  4. java 生成器 设计模式_Java中的生成器设计模式
  5. tnsnames.ora配置未生效_1分钟了解网络交换机的6种命令配置模式
  6. opencv python 直方图反向投影_python OpenCV学习笔记直方图反向投影的实现
  7. 识别物体是否存在_【科学实践Vol.1】带你玩转“人脸识别”
  8. 零配置构建工具:parcel
  9. CentOS / RHEL Cachefiles 加速网络文件系统NFS访问速度
  10. [MSDN]Design Guidelines for Developing Class Libraries with .NET Framework 4
  11. windows redis 设置密码_Linux下设置redis访问密码
  12. VS2015番茄安装教程
  13. 内存颗粒和闪存颗粒的区别_slc、mlc、tlc闪存芯片颗粒哪个好?有什么区别?
  14. 事件绑定,事件类型,事件委托
  15. elasticsearch7.x catAPI之indices
  16. 浙江工业大学计算机技术专业考研经验分享帖
  17. 我要学编程,看什么书好?--^_^,这里推荐一些个人觉得很不错的书
  18. 内部乙方部门的转型之困
  19. python蓝桥算法提高
  20. 适用于老版本的魔兽世界登陆器编写指南

热门文章

  1. java 推送消息页面_Notification API,为你的网页添加桌面通知推送
  2. java exec mvn_maven---常用插件之EXEC
  3. C++ chrono 库中的 steady_clock 、 system_clock、high_resolution_clock区别
  4. osg::ComputeBoundsVisitor用法(一)
  5. android 清空canvas部分内容_Android自定义View实现圆形头像效果
  6. 人工智能是互联网下一轮变革的核心
  7. 实现 VUE 中 MVVM - step10 - Computed
  8. IIS 5.0 和 6.0 的 ASP.NET 应用程序生命周期概述
  9. js中cookie操作
  10. 联发科看上AMD“女友”GF:全新22nm处理器来了