2016-01-20 9 views
18

Ich versuche, den Workflow für das Trainieren und Bereitstellen eines Tensorflow-Modells für Android herauszufinden. Ich bin mir der anderen Fragen auf StackOverflow bewusst, aber keine von ihnen scheint die Probleme zu lösen, mit denen ich konfrontiert bin.Ausführen eines Tensorflow-Modells unter Android

Nach dem Android Beispiel aus dem Tensorflow Repository zu studieren, das ist, was ich denke, der Workflow sein sollte:

  1. Erstellen und trainieren Tensorflow Modell in Python.
  2. Erstellen Sie ein neues Diagramm und übertragen Sie alle relevanten Knoten (d. H. Nicht die Knoten, die für das Training zuständig sind) auf dieses neue Diagramm. Trainierte Gewichtungsvariablen werden als Konstanten importiert, damit sie von der C++ - API gelesen werden können.
  3. Entwickeln Sie die Android-GUI in Java, indem Sie das native Schlüsselwort verwenden, um einen Aufruf an das Tensorflow-Modell auszugeben.
  4. Führen Sie Java aus, um den C/C++ - Stubcode für den nativen Tensorflow-Aufruf zu generieren.
  5. Füllen Sie den Stub aus, indem Sie die Tensorflow C++ API verwenden, um das trainierte/serialisierte Modell einzulesen und darauf zuzugreifen.
  6. Verwenden Sie Bazel, um sowohl die Java-App, die native Tensorflow-Schnittstelle (als .so-Datei) zu erstellen, als auch die APK zu generieren.
  7. Verwenden Sie adb zum Bereitstellen der APK.

    Schritt 6 ist das Problem. Bazel kompiliert gerne eine native (zu OSX) .dylib, die ich über JNI von Java aus aufrufen kann. Android Studio erzeugt ebenfalls eine ganze Menge XML-Code, der die gewünschte GUI erzeugt. Bazel möchte jedoch, dass sich der gesamte Code der Java-App im Topspace-Verzeichnis "WORKSPACE" (im Tensorflow-Repo) befindet, und Android Studio verknüpft sofort alle Arten von externen Bibliotheken aus dem SDK, um GUIs zu erstellen (ich weiß, weil meine Bazel-Kompilierungslauf schlägt fehl, wenn er diese Ressourcen nicht finden kann). Die einzige Möglichkeit, Bazel zu zwingen, eine .so-Datei kompilieren zu lassen, besteht darin, sie zu einer abhängigen Regel einer Android-Regel zu machen. Ein direktes Cross-Compilieren einer nativen Bibliothek ist das, was ich am liebsten meine A.S. Code zu einem Bazel-Projekt.

    Wie quadriere ich das? Bazel wird angeblich Android-Code kompilieren, aber Android Studio generiert Code, den Bazel nicht kompilieren kann. Alle Beispiele von Google geben Ihnen einfach Code von einem Repo ohne irgendeinen Hinweis darauf, wie es erzeugt wurde. Soweit ich weiß, soll das XML, das Teil einer Android Studio App ist, nicht von Hand erstellt werden. Wenn es von Hand gemacht werden kann, wie vermeide ich die Notwendigkeit für all diese externen Bibliotheken?

    Vielleicht bekomme ich den Workflow falsch, oder es gibt einen Aspekt von Bazel/Android Studio, den ich nicht verstehe. Jede Hilfe wird geschätzt.

Vielen Dank!

Edit:

Es gab einige Dinge, die ich, dass erfolgreich in die Bibliothek Gebäude beigetragen hätte tun endete:

  1. ich auf die neueste Bazel aktualisiert.
  2. Ich baute TensorFlow aus der Quelle.
  3. implementiert ich die empfohlene Bazel unter Datei BUILD, mit einem paar Ergänzungen (aus dem Android Beispiel genommen):

    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", 
        ], 
    ) 
    

Ich habe nicht nachgewiesen, dass diese Bibliothek geladen und in Android verwendet werden kann, noch; Android Studio 1.5 scheint sehr heikel zu sein, das Vorhandensein von nativen Bibliotheken anzuerkennen.

+0

Die Erstellung einer .dylib wird nicht helfen, da Android nicht OSX-dylib ist, ist nur ein OSX-Format. Es ist Linux, Sie müssen ein .so (das ist ziemlich das Gleiche Feature-weise, aber ein anderes Dateiformat). Auch das XML in Android wird von Hand NICHT generiert. In den Google-Beispielen wird so gut wie nichts generiert. Die Tatsache, dass Sie es erwarten, ist wahrscheinlich ein Teil Ihres Problems. –

+0

Auch wenn Ihre Tensorflow-Software Bazel nicht verwenden muss, habe ich noch nie davon gehört, dass es für Android-Arbeit verwendet wird. Gradle ist der neue Standard, und Ant ist der Legacy-Standard. Wenn du Bazel benutzt, bist du entweder blutig oder du machst dein eigenes Ding. –

+0

@amm Konnten Sie es auf Android ausführen, was ist die Größe der App, die Sie gebaut haben? – sau

Antwort

10

Nachdem ein Android NDK in Ihrem Arbeitsbereich-Datei einrichten, Bazel können eine .so für Android Cross-kompilieren, wie folgt aus:

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 \ 
    [email protected]_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 wants all of the java app code to be inside the 'WORKSPACE' top-level directory (in the Tensorflow repo)

Wenn 0.1.4 freigegeben (drückt es jetzt) und wir haben einige Korrekturen an TensorFlow und Protobuf vorgenommen. Sie können den TensorFlow-Repo als Remote-Repository verwenden. Nach dem Einrichten in Ihrer WORKSPACE-Datei können Sie dann auf TensorFlow-Regeln mit @tensorflow//foo/bar Etiketten verweisen.

+0

Da Sie höchstwahrscheinlich ein Mitglied der [Bazel-Gruppe] (https://github.com/ulfjack/bazel/graphs/contributors) sind, können Sie es in Ihrem [SO-Profil] (http://stackoverflow.com/users) notieren/4731056/Ulf-Adams). Ich bin eher geneigt, eine Antwort aufzuschreiben, wenn ich weiß, dass die antwortende Person ein Mitglied des Entwicklungsteams ist. –

+0

Was ich mit dem Kommentar meine: Ich kann meinen App-Code nicht in einer Verzeichnisstruktur getrennt von der Tensorflow-Wurzel speichern. – amm

+0

Diese Lösung funktioniert nicht für mich. Fehlermeldung: "FEHLER: Keine Toolchain für CPU 'Darwin' gefunden." Ich habe android_sdk_repository() und android_ndk_repository() in meiner WORKSPACE-Datei definiert. – amm

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

Hinweis: --recurse-submodule ist wichtig, Submodule zu ziehen.

Installieren Sie Bazel von hier. Bazel ist das primäre Build-System für TensorFlow. Editieren Sie nun den WORKSPACE, wir können die WORKSPACE-Datei im Stammverzeichnis des TensorFlow finden, das wir zuvor geklont haben.

# 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) 

Wie unten mit unserer sdk und NDK Pfad:

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) 

dann die .so-Datei erstellen.

bazel build -c opt //tensorflow/contrib/android:libtensorflow_inference.so \ 
    --crosstool_top=//external:android/crosstool \ 
    [email protected]_tools//tools/cpp:toolchain \ 
    --cpu=armeabi-v7a 

Wir ersetzen armee-v7a mit unserer gewünschten Zielarchitektur. Die Bibliothek wird auf befinden:

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

Um die Java-Pendant bauen:

bazel build //tensorflow/contrib/android:android_tensorflow_inference_java 

Wir können die JAR-Datei finden:

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

Jetzt haben wir beiden Gläser und. so Datei. Ich habe bereits beide .so Datei und jar, können Sie direkt von der project verwenden.

Setzen Sie libandroid_tensorflow_inference_java.jar in den libs-Ordner und klicken Sie mit der rechten Maustaste und fügen Sie sie als Bibliothek hinzu.

compile files('libs/libandroid_tensorflow_inference_java.jar') 

erstellen jniLibs Ordner in Hauptverzeichnis und setzt libtensorflow_inference.so in jniLibs/armeabi-V7A/Ordner.

Nun können wir die TensorFlow Java API aufrufen.

Die TensorFlow-Java-API hat alle erforderlichen Methoden über eine Klasse TensorFlowInferenceInterface verfügbar gemacht.

Nun müssen wir die TensorFlow Java API mit dem Modellpfad aufrufen und laden.

Ich habe einen vollständigen Blog here geschrieben.