android ndk怎样加载o文件_在Android中使用TFLite c++部署
之前的文章中,我們跟大家介紹過如何使用NNAPI來加速TFLite-Android的inference(可參考使用NNAPI加速android-tflite的Mobilenet分類器)。不過之前介紹的文章,在進(jìn)行模型加載和推斷使用的是官方提供的預(yù)編譯好的Jar文件,業(yè)務(wù)代碼都通過Java進(jìn)行編寫。如果你想使用C++在native層進(jìn)行業(yè)務(wù)代碼的編寫,你也可以參考本文的實(shí)現(xiàn)思路。跟之前專欄中介紹的框架一樣,我們首先需要進(jìn)行框架的編譯 — TFLite的庫函數(shù)編譯。我們先下載最新版本master分支的tensorflow源碼。
git clone https://github.com/tensorflow/tensorflow在下載好源碼以后,我需要進(jìn)入tensorflow文件夾目錄下,然后進(jìn)行配置。在此之前,你還需要確保NDK和Bazel安裝的正確性,本文采用的NDK為ndk-r17c,bazel采用的版本為 0.24.1。
cd tensorflow ./configure配置完畢后,你還需要在該目錄下的WORKSPACE文件中添加ndk的環(huán)境,直接在文件的末尾加入如下參數(shù)即可,
android_ndk_repository(name = "androidndk", # Required. Name *must* be "androidndk".api_level = 21, )本文在RK3288開發(fā)板進(jìn)行驗(yàn)證,Android系統(tǒng)為5.1版本。所以為了兼容,這里采用的APP_PLATFORM為21,對(duì)應(yīng)于api_level為21。下面,我們開始進(jìn)行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這里面有幾個(gè)參數(shù)需要注意,一個(gè)是--fat_apk_cpu和--config。在Android平臺(tái)中一般fat_apk_cpu可取arm64-v8a或armeabi-v7a,config可選為android_arm64或android_arm。更詳細(xì)的配置大家可參考/tensorflow/lite/build_def.bzl該文件。
編譯好的模型libtensorflowlite.so會(huì)保存在/tensorflow/bazel-bin/tensorflow/lite文件夾中,下面我們開始配置依賴環(huán)境,進(jìn)行C++業(yè)務(wù)代碼的編寫。配置環(huán)境大家可參考如下mk腳本,注意將環(huán)境變量替換成你本機(jī)的環(huán)境變量。需要注意的地方,引入tensorflow的頭文件路徑的同時(shí),也需要引入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++業(yè)務(wù)代碼,跟在java中的調(diào)用邏輯是一樣的,先加載模型,然后進(jìn)行解析;輸入數(shù)據(jù)時(shí)候要根據(jù)訓(xùn)練時(shí)的預(yù)處理方式,進(jìn)行對(duì)等的預(yù)處理操作;最后執(zhí)行inference,取出結(jié)果,如有后處理,再進(jìn)行相應(yīng)的后處理。
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++進(jìn)行TFlite模型的部署。目前TFLIte在嵌入式端的競爭力雖然不是很強(qiáng),但是開發(fā)的活躍度依舊很高,推出了許多新的特性,如xla、int8、量化、fp16,以及配套的離線量化、壓縮腳本,后續(xù)本專欄會(huì)持續(xù)關(guān)注TFlite在嵌入式端的進(jìn)展。歡迎大家留言討論、關(guān)注本專欄,謝謝大家。
實(shí)戰(zhàn)嵌入端的AI算法?zhuanlan.zhihu.com 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的android ndk怎样加载o文件_在Android中使用TFLite c++部署的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: django ajax 更新表格_Dja
- 下一篇: s3c2440移植MQTT