在Android

时间:2016-01-20 00:46:34

标签: android tensorflow bazel

我正在尝试找出在Android上培训和部署Tensorflow模型的工作流程。我知道在StackOverflow上有类似于这个的其他问题,但它们似乎都没有解决我遇到的问题。

在研究了Tensorflow存储库中的Android示例之后,我认为这应该是工作流程:

  1. 在Python中构建和训练Tensorflow模型。
  2. 创建一个新图表,并将所有相关节点(即不负责培训的节点)传输到此新图表。训练有素的权重变量作为常量导入,以便C ++ API可以读取它们。
  3. 用Java开发Android GUI,使用native关键字来存根对Tensorflow模型的调用。
  4. 运行javah以生成Tensorflow本机调用的C / C ++存根代码。
  5. 使用Tensorflow C ++ API填写存根,读入并访问经过培训/序列化的模型。
  6. 使用Bazel构建Java应用程序,本机Tensorflow接口(作为.so文件),并生成APK。
  7. 使用adb部署APK。

    第6步是问题所在。 Bazel很乐意编译一个本机(到OSX).dylib,我可以通过JNI从Java调用它。同样,Android Studio将生成一大堆XML代码,这些代码构成了我想要的GUI。但是,Bazel希望所有java应用程序代码都在'WORKSPACE'顶级目录(在Tensorflow repo中)中,并且Android Studio会立即链接到SDK中的各种外部库以生成GUI(我知道因为我的Bazel编译运行失败,因为它找不到这些资源)。我可以找到迫使Bazel交叉编译.so文件的唯一方法是使其成为Android规则的依赖规则。直接交叉编译本机库是我更喜欢移植我的A.S.代码到Bazel项目。

    我该怎样对待这个?据说Bazel会编译Android代码,但Android Studio会生成Bazel无法编译的代码。来自Google的所有示例都只是从回购中提供代码,而不知道它是如何生成的。据我所知,属于Android Studio应用程序的XML应该是生成的,而不是手工制作的。如果可以手工制作,我如何避免需要所有这些外部库?

    也许我的工作流程出错了,或者Bazel / Android Studio的某些方面我不理解。任何帮助赞赏。

  8. 谢谢!

    修改

    我最终做了几件事可能有助于图书馆建设成功:

    1. 我升级到最新的Bazel。
    2. 我从源头重建了TensorFlow。
    3. 我在下面实现了推荐的Bazel BUILD文件,添加了一些内容(取自Android示例):

      cc_binary(
      name = "libName.so",
      srcs = ["org_tensorflowtest_MyActivity.cc", 
              "org_tensorflowtest_MyActivity.h",
              "jni.h",
              "jni_md.h",
              ":libpthread.so"],
      deps = ["//tensorflow/core:android_tensorflow_lib",
              ],
      copts = [
          "-std=c++11",
          "-mfpu=neon",
          "-O2",
      ],
      linkopts = ["-llog -landroid -lm"],
      linkstatic = 1,
      linkshared = 1,
      )
      
      cc_binary(
           name = "libpthread.so",
           srcs = [],
           linkopts = ["-shared"],
           tags = [
               "manual",
               "notap",
           ],
      )
      
    4. 我还没有确认此库可以在Android中加载和使用; Android Studio 1.5在承认本机库的存在方面似乎非常挑剔。

2 个答案:

答案 0 :(得分:10)

在您的WORKSPACE文件中设置Android NDK之后,Bazel可以交叉编译Android的.so,如下所示:

cc_binary(
    name = "libfoo.so",
    srcs = ["foo.cc"],
    deps = [":bar"],
    linkstatic = 1,
    linkshared = 1,
)

$ bazel build foo:libfoo.so \
    --crosstool_top=//external:android/crosstool --cpu=armeabi-v7a \
    --host_crosstool_top=@bazel_tools//tools/cpp:toolchain
$ file bazel-bin/foo/libfoo.so
bazel-bin/foo/libfoo.so: ELF 32-bit LSB  shared object, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), not stripped
  

Bazel希望所有的Java应用程序代码都在' WORKSPACE'   顶级目录(在Tensorflow仓库中)

当0.1.4发布时(现在推送它)并且我们已经将一些修复推送到TensorFlow和Protobuf,您可以开始使用TensorFlow仓库作为远程存储库。在WORKSPACE文件中进行设置后,您可以使用@tensorflow//foo/bar标签引用TensorFlow规则。

答案 1 :(得分:1)

git clone --recurse-submodules https://github.com/tensorflow/tensorflow.git

注意: - recurse-submodules对于拉取子模块非常重要。

从这里安装Bazel。 Bazel是TensorFlow的主要构建系统。 现在,编辑WORKSPACE,我们可以在之前克隆的TensorFlow的根目录中找到WORKSPACE文件。

# Uncomment and update the paths in these entries to build the Android demo.
#android_sdk_repository(
#    name = "androidsdk",
#    api_level = 23,
#    build_tools_version = "25.0.1",
#    # Replace with path to Android SDK on your system
#    path = "<PATH_TO_SDK>",
#)
#
#android_ndk_repository(
#    name="androidndk",
#    path="<PATH_TO_NDK>",
#    api_level=14)

如下所示我们的sdk和ndk路径:

android_sdk_repository(
    name = "androidsdk",
    api_level = 23,
    build_tools_version = "25.0.1",
    # Replace with path to Android SDK on your system
    path = "/Users/amitshekhar/Library/Android/sdk/",
)
android_ndk_repository(
    name="androidndk",
    path="/Users/amitshekhar/Downloads/android-ndk-r13/",
    api_level=14)

然后构建.so文件。

bazel build -c opt //tensorflow/contrib/android:libtensorflow_inference.so \
   --crosstool_top=//external:android/crosstool \
   --host_crosstool_top=@bazel_tools//tools/cpp:toolchain \
   --cpu=armeabi-v7a

用我们想要的目标架构替换armeabi-v7a。 该图书馆位于:

bazel-bin/tensorflow/contrib/android/libtensorflow_inference.so

构建Java版本:

bazel build //tensorflow/contrib/android:android_tensorflow_inference_java

我们可以在以下位置找到JAR文件:

bazel-bin/tensorflow/contrib/android/libandroid_tensorflow_inference_java.jar

现在我们有jar和.so文件。我已经构建了.so文件和jar,你可以直接使用project

将libandroid_tensorflow_inference_java.jar放入libs文件夹并右键单击并添加为库。

compile files('libs/libandroid_tensorflow_inference_java.jar')

在主目录中创建jniLibs文件夹,并将libtensorflow_inference.so放在jniLibs / armeabi-v7a /文件夹中。

现在,我们将能够调用TensorFlow Java API。

TensorFlow Java API通过类TensorFlowInferenceInterface公开了所有必需的方法。

现在,我们必须使用模型路径调用TensorFlow Java API并加载它。

我写了一篇完整的博客here