ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

在Android Studio Project中使用tensorflow lite C API的问题

2019-06-11 04:20:26  阅读:586  来源: 互联网

标签:c-2 android android-ndk tensorflow android-studio-3-0


我目前正在研究一个关于神经网络的项目.
为此,我想构建一个Android应用程序,它应该使用tensorflow [lite]来解决一些对象检测/识别问题.

因为我希望代码尽可能地可移植,所以我想用C编写大部分代码,因此使用tensorflow lite的C API而不是Java API / wrapper.
因此,我修改了tensorflow / contrib / lite / BUILD并添加了以下内容以便能够创建共享张量流库.

cc_binary(
name = "libtensorflowLite.so",

linkopts=["-shared", "-Wl"],
linkshared=1,

copts = tflite_copts(),
deps = [
    ":framework",
    "//tensorflow/contrib/lite/kernels:builtin_ops",
],

)

(这是基于这个问题的答案:https://github.com/tensorflow/tensorflow/issues/17826)

然后我用了

bazel build //tensorflow/contrib/lite:libtensorflowLite.so --crosstool_top=//external:android/crosstool --cpu=arm64-v8a --host_crosstool_top=@bazel_tools//tools/cpp:toolchain --cxxopt="-std=c++11"

最终建立它.

之后我转向Android Studio并设置了一个基本项目.
为了将共享库添加到项目中,我参考了这个示例:

https://github.com/googlesamples/android-ndk/tree/840858984e1bb8a7fab37c1b7c571efbe7d6eb75/hello-libs

我还为flatbuffers添加了所需的依赖项.

构建/编译过程成功,没有任何链接器错误(好吧,至少在尝试了几个小时之后……).

然后APK成功安装在Android设备上,但在启动后立即崩溃. Logcat提供以下输出:

04-14 20:09:59.084 9623-9623/com.example.hellolibs E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.hellolibs, PID: 9623
    java.lang.UnsatisfiedLinkError: dlopen failed: library "/home/User/tensorflowtest/app/src/main/cpp/../../../../distribution/tensorflow/lib/x86/libtensorflowLite.so" not found
        at java.lang.Runtime.loadLibrary0(Runtime.java:1016)
        at java.lang.System.loadLibrary(System.java:1657)
        at com.example.hellolibs.MainActivity.<clinit>(MainActivity.java:36)
        at java.lang.Class.newInstance(Native Method)
        at android.app.Instrumentation.newActivity(Instrumentation.java:1174)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2669)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
        at android.app.ActivityThread.-wrap11(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6494)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

我在Android x86模拟器和真正的arm64-v8a安卓智能手机上试过这个.

所以对我来说,这似乎在启动时应用程序尝试加载tensorflowLite共享库,但无法找到它.
使用zip存档管理器打开apk我可以验证平台(arm,x86)依赖的.so文件是否按预期打包到APK中(通过将以下内容添加到build.gradle:

sourceSets {
        main {
            // let gradle pack the shared library into apk
            jniLibs.srcDirs = ['../distribution/tensorflow/lib']
        }
})

我不明白为什么它在我把它放在我的Ubuntu 17.10 PC上的路径中查找库.
所以,我认为我在尝试调整将外部库添加到我之前提到的Android Studio项目的示例时犯了一个错误.
这就是我下载整个项目并在Android Studio中打开它并验证该示例按预期工作的原因.之后我用libtensorflowLite.so替换了示例libgperf.so,并保留了其他所有内容,尤其是CMakeLists.txt.
但我再次得到完全相同的错误,因此我怀疑这是libtensorflowLite库本身的问题,而不是android项目(虽然这只是我的猜测).

我正在开发android studio 3.1.1,NDK Version 14和API Level 24(Android 7.0).
如果有人知道可能出现的问题,那么任何帮助都会受到高度赞赏.
我也对任何其他方法开放,这些方法允许我对一个Android应用程序使用带有C的tensorflow lite.

非常感谢,

马丁

解决方法:

我记得几个星期前我问过这个问题.
同时,我找到了解决问题的方法,TensorflowLite现已很好地嵌入到我的Android项目中,在那里我使用C API进行所有编程!

问题是我构建的Tensorflow共享库没有包含soname.因此,在构建过程中,库被剥离,并且由于没有找到名称,因此路径被用作“名称”.我注意到,当我使用linux“strings”工具进一步调查我的native-lib.so(NDK C库,然后由App加载).在这里,我发现确实从“/home/User/tensorflowtest/app/src/main/cpp/../../../../distribution/tensorflow/lib/x86/libtensorflowLite加载库的路径.so“已定.
将“-Wl,-soname = libtensorflowLite.so”添加到BUILD文件中的构建选项可修复此问题!你可以找到我在下面使用的整个规则.

由于缺乏解释,所以设置一切都很痛苦(似乎TensorflowLite主要通过Android上的Java API使用?),我想简要介绍如何在Android Studio中使用TensorflowLite的C API(来自Android NDK项目).

1.为您的架构构建库

要使用C API,首先需要构建TensorflowLite库.为此,将以下规则添加到tensorflow / contrib / lite中的BUILD文件中:

cc_binary(

name = "libtensorflowLite.so",
linkopts=[
    "-shared", 
    "-Wl,-soname=libtensorflowLite.so",
],
linkshared = 1,
copts = tflite_copts(),
deps = [
    ":framework",
    "//tensorflow/contrib/lite/kernels:builtin_ops",
],

)

注意:有了这个,就可以构建一个共享库!静态的也可能有效.

现在您可以使用构建库

bazel build //tensorflow/contrib/lite:libtensorflowLite.so --crosstool_top=//external:android/crosstool --cpu=arm64-v8a --host_crosstool_top=@bazel_tools//tools/cpp:toolchain --cxxopt="-std=c++11"

如果要支持多种体系结构,则必须多次构建库并相应地更改–cpu标志.

注意:这至少对于arm64-v8a和armeabi-v7a(没有使用MIPS进行测试,因此这可能会起作用)也能正常工作.但是在x86设备上,我收到了本主题中已经解决的“atomic_store_8”错误:https://github.com/tensorflow/tensorflow/issues/16589

2.添加要包含在Android Studio项目中的库和所需的标头

构建了库之后,您现在需要确保它也链接到您的应用程序中(更具体地说:进入您的Android NDK库,在我的例子中命名为“native-lib”).我将简要介绍如何执行此操作,但是如果您需要更详细的说明,可以参考我在初始问题中提供的github链接:https://github.com/googlesamples/android-ndk/tree/840858984e1bb8a7fab37c1b7c571efbe7d6eb75/hello-libs

2.1.在Android Studio项目中,打开CMakeLists.txt

2.2.添加以下内容:

    # This will create a new "variable" holding the path to a directory
    # where we will put our library and header files.
    # Change this to your needs
    set(distribution_DIR ${CMAKE_SOURCE_DIR}/distribution)

    # This states that there exists a shared library called libtensorflowLite
    # which will be imported (means it is not built with the rest of the project!)
    add_library(libtensorflowLite SHARED IMPORTED)

    # This indicates where the libtensorflowLite.so for each architecture is found relative to our distribution directory
    set_target_properties(libtensorflowLite PROPERTIES IMPORTED_LOCATION
        ${distribution_DIR}/lib/${ANDROID_ABI}/libtensorflowLite.so)

    # This indicates where the header files are found relative to our distribution dir
    target_include_directories(native-lib PRIVATE
                       ${distribution_DIR}/include)

    # Finally, we make sure our libtensorflowLite.so is linked to our native-lib and loaded during runtime 
    target_link_libraries( # Specifies the target library.
                   native-lib
                   libtensorflowLite
                   # Links the target library to the log library
                   # included in the NDK.
                   ${log-lib} )

2.3.打开Module:App的build.gradle(不是项目的!)

2.4.确保我们的图书馆将被打包到您的APK中

在Android部分中添加:

    sourceSets {
        main {
            // let gradle pack the shared library into apk
            jni.srcDirs = []
            jniLibs.srcDirs = ['distribution/lib']
        }
    }

您可能需要编辑符合您需求的路径:此处的文件将打包到lib目录中的.apk中.

3.包括flatbuffers

TensorflowLite使用flatbuffers序列化库.我想如果你使用bazel构建项目,这将自动添加.但使用Android Studio时并非如此.
当然,您也可以添加静态库或共享库.
但是,对我来说,最简单的方法是让flatbuffers每次使用我的应用程序的其余部分进行编译(它不是那么大).
我将所有flatbuffers * .cpp源文件复制到我的项目中,并将它们添加到CMakeLists中.

4.复制TensorflowLite和flatbuffers所需的标头

在3.我刚刚将cpp文件复制到我的项目中.
但是,头文件需要位于我们在步骤2.2中在target_include_directories中设置的目录中.

因此,继续将所有flatbuffers(来自flatbuffers存储库)* .h文件复制到此目录.
接下来,从TensorflowLite存储库中,您需要tensorflow / contrib / lite目录中的所有头文件.但是,您应该保留文件夹结构

对我来说,它看起来像这样:

>分配

> lib

> arm64-v8a

> libtensorflowLite

> armeabi-v7a

> libtensorflowLite

>包括

> flatbuffers
> tensorflow

>贡献

>精简版

>内核
> nnapi
>架构
>工具

所以,如果我没有忘记任何事情,现在应该正确设置!
希望这有帮助,它对你有用,就像它对我一样;)

最好的祝福,

马丁

标签:c-2,android,android-ndk,tensorflow,android-studio-3-0
来源: https://codeday.me/bug/20190611/1216116.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有