2016-01-20 31 views
18

Sto cercando di capire il flusso di lavoro per la formazione e la distribuzione di un modello Tensorflow su Android. Sono a conoscenza delle altre domande simili a questa su StackOverflow, ma nessuno di loro sembra affrontare i problemi che ho incontrato.Esecuzione di un modello Tensorflow su Android

Dopo aver studiato l'esempio Android dal repository tensorflow, questo è quello che penso il flusso di lavoro dovrebbe essere:

  1. costruire e formare tensorflow modello in Python.
  2. Creare un nuovo grafico e trasferire tutti i nodi rilevanti (ovvero non i nodi responsabili dell'addestramento) a questo nuovo grafico. Le variabili di peso addestrate vengono importate come costanti in modo che l'API C++ possa leggerle.
  3. Sviluppare la GUI Android in Java, utilizzando la parola chiave nativa per eseguire una chiamata al modello Tensorflow.
  4. Eseguire javah per generare il codice stub C/C++ per la chiamata nativa di Tensorflow.
  5. Completare lo stub utilizzando l'API C++ di Tensorflow per leggere e accedere al modello addestrato/serializzato.
  6. Utilizzare Bazel per costruire ENTRAMBI l'app Java, l'interfaccia nativa di Tensorflow (come file .so) e generare l'APK.
  7. Utilizzare adb per distribuire l'APK.

    Il passaggio 6 è il problema. Bazel compilerà felicemente un nativo (su OSX) .dylib che posso chiamare da Java tramite JNI. Allo stesso modo, Android Studio genererà un sacco di codice XML che rende la GUI che voglio. Tuttavia, Bazel vuole che tutto il codice dell'app java sia nella directory di primo livello "WORKSPACE" (nel repository Tensorflow), e Android Studio collega immediatamente tutti i tipi di librerie esterne dall'SDK per creare GUI (lo so perché il mio L'esecuzione di compilazione di Bazel fallisce quando non riesce a trovare queste risorse). L'unico modo che riesco a trovare per forzare Bazel a compilare a croce un file .so è rendendolo una regola dipendente di una regola Android. La cross-compilazione diretta di una lib nativa è ciò che preferirei per il porting della mia A.S. codice per un progetto Bazel.

    Come si piazza questo? Apparentemente Bazel compilerà il codice Android, ma Android Studio genera codice che Bazel non può compilare. Tutti gli esempi di Google ti danno semplicemente il codice da un pronti contro termine senza alcun indizio su come è stato generato. Per quanto ne so, l'XML che fa parte di un'app Android Studio dovrebbe essere generato, non creato a mano. Se può essere fatto a mano, come evitare la necessità di tutte quelle librerie esterne?

    Forse sto sbagliando il flusso di lavoro o ci sono alcuni aspetti di Bazel/Android Studio che non capisco. Qualsiasi aiuto apprezzato.

Grazie!

Edit:

C'erano molte cose che ho finito per fare che potrebbero aver contribuito alla costruzione delle biblioteche con successo:

  1. ho aggiornato all'ultima Bazel.
  2. Ho rigenerato TensorFlow dalla sorgente.
  3. ho implementato il Bazel consigliato build di seguito, con alcune aggiunte (tratti dalla esempio 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", 
        ], 
    ) 
    

non ho verificato che questa libreria può essere caricato e utilizzato in Android ancora; Android Studio 1.5 sembra essere molto schizzinoso nel riconoscere la presenza di librerie native.

+0

Creare un .dylib non è di alcuna utilità, poiché Android non è OSX- dylib è un formato solo OSX. È linux, è necessario creare un .so (che è più o meno la stessa funzione di funzionalità, ma un diverso formato di file). Inoltre, l'XML in Android è tutto fatto a mano NON generato. Praticamente non viene generato nulla in nessuno degli esempi di Google. Il fatto che ti aspetti che sia probabilmente è parte del tuo problema. –

+0

Inoltre, a meno che il software Tensorflow non debba utilizzare Bazel, non ho mai sentito di utilizzarlo per il lavoro su Android. Gradle è il nuovo standard e Ant è lo standard legacy. Se stai usando Bazel, stai sanguinando o stai facendo tutto da solo. –

+0

@amm Eri in grado di eseguirlo su Android qual è la dimensione dell'app che hai costruito? – sau

risposta

10

Dopo la creazione di un NDK Android nel file di lavoro, Bazel può attraversare-compilare un .so per Android, in questo modo:

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)

Quando 0.1.4 viene rilasciato (spingendolo in questo momento) e abbiamo apportato alcune correzioni a TensorFlow e Protobuf, è possibile iniziare a utilizzare il repository TensorFlow come repository remoto. Dopo averlo impostato nel file WORKSPACE, è possibile fare riferimento alle regole di TensorFlow utilizzando le etichette @tensorflow//foo/bar.

+0

Dal momento che molto probabilmente un membro del [gruppo Bazel] (https://github.com/ulfjack/bazel/graphs/contributors) può annotarlo nel [profilo SO] (http://stackoverflow.com/users/4731056/ULF-Adams). Sono più propenso a revocare una risposta se so che la persona che risponde è un membro del team di sviluppo. –

+0

Cosa intendo per commento: non riesco a mantenere il mio codice app in una struttura di directory separata dalla radice di Tensorflow. – amm

+0

Questa soluzione non funziona per me. Messaggio di errore: "ERRORE: nessuna toolchain trovata per cpu 'darwin'." Ho android_sdk_repository() e android_ndk_repository() definiti nel mio file WORKSPACE. – amm

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

Nota: - i sottomoduli di recupero sono importanti per il pull dei moduli.

Installa Bazel da qui. Bazel è il sistema di compilazione principale per TensorFlow. Ora, modifica il WORKSPACE, possiamo trovare il file WORKSPACE nella directory root del TensorFlow che abbiamo clonato in precedenza.

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

come di seguito con il nostro SDK e NDK percorso:

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) 

quindi creare il file .so.

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

Sostituzione di armeabi-v7a con l'architettura di destinazione desiderata. La biblioteca sarà ubicato a:

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

Per costruire la controparte Java:

bazel build //tensorflow/contrib/android:android_tensorflow_inference_java 

possiamo trovare il file JAR in:

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

Ora abbiamo sia vaso e. quindi file. Ho già creato entrambi i file .so e jar, puoi utilizzare direttamente dallo project.

Inserire libandroid_tensorflow_inference_java.jar nella cartella libs e fare clic con il tasto destro del mouse e aggiungere come libreria.

compile files('libs/libandroid_tensorflow_inference_java.jar') 

Crea cartella jniLibs nella directory principale e mettere in libtensorflow_inference.so jniLibs/armeabi-V7A/cartella.

Ora, saremo in grado di chiamare l'API Java di TensorFlow.

L'API Java TensorFlow ha esposto tutti i metodi richiesti tramite una classe TensorFlowInferenceInterface.

Ora, dobbiamo chiamare l'API Java di TensorFlow con il percorso del modello e caricarlo.

Ho scritto un blog completo here.

Problemi correlati