code - Ejecutando un modelo Tensorflow en Android
tensorflow python github (2)
Estoy tratando de averiguar el flujo de trabajo para la capacitación y la implementación de un modelo Tensorflow en Android. Soy consciente de las otras preguntas similares a esta en StackOverflow, pero ninguna de ellas parece abordar los problemas que he encontrado.
Después de estudiar el ejemplo de Android del repositorio de Tensorflow, esto es lo que creo que debería ser el flujo de trabajo:
- Construye y entrena el modelo Tensorflow en Python.
- Cree un nuevo gráfico y transfiera todos los nodos relevantes (es decir, no los nodos responsables de la capacitación) a este nuevo gráfico. Las variables de peso entrenadas se importan como constantes para que la API de C ++ pueda leerlas.
- Desarrolle la GUI de Android en Java, utilizando la palabra clave nativa para anular una llamada al modelo Tensorflow.
- Ejecute javah para generar el código de código auxiliar C / C ++ para la llamada nativa Tensorflow.
- Complete el código auxiliar utilizando la API de Tensorflow C ++ para leer y acceder al modelo entrenado / serializado.
- Utilice Bazel para compilar TANTO la aplicación Java, la interfaz Tensorflow nativa (como un archivo .so) y generar el APK.
Usa adb para desplegar el APK.
El paso 6 es el problema. Bazel compilará felizmente un .dylib nativo (a OSX) que puedo llamar desde Java a través del JNI. Asimismo, Android Studio generará un montón de código XML que hace que la GUI que quiero. Sin embargo, Bazel desea que todo el código de la aplicación java esté dentro del directorio de nivel superior ''WORKSPACE'' (en el repositorio de Tensorflow), y Android Studio enlaza inmediatamente en todo tipo de bibliotecas externas desde el SDK para hacer GUI (lo sé porque mi La ejecución de la compilación de Bazel falla cuando no puede encontrar estos recursos). La única forma que puedo encontrar para forzar a Bazel a compilar de forma cruzada un archivo .so es hacerlo una regla dependiente de una regla de Android. La compilación directa de una biblioteca nativa es lo que preferiría trasladar mi código AS a un proyecto Bazel.
¿Cómo puedo cuadrar esto? Bazel supuestamente compilará el código de Android, pero Android Studio genera un código que Bazel no puede compilar. Todos los ejemplos de Google simplemente le dan el código de un repositorio sin ninguna pista sobre cómo se generó. Por lo que sé, el XML que forma parte de una aplicación de Android Studio se debe generar, no a mano. Si se puede hacer a mano, ¿cómo evito la necesidad de todas esas bibliotecas externas?
Tal vez me esté equivocando con el flujo de trabajo, o hay algún aspecto de Bazel / Android Studio que no entiendo. Cualquier ayuda apreciada.
¡Gracias!
Editar:
Terminé haciendo varias cosas que podrían haber contribuido al edificio de la biblioteca con éxito:
- Me actualicé a la última Bazel.
- Reconstruí TensorFlow desde la fuente.
Implementé el archivo de Bazel BUILD recomendado a continuación, con algunas adiciones (tomadas del ejemplo de 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", ], )
No he verificado que esta biblioteca pueda cargarse y usarse todavía en Android; Android Studio 1.5 parece ser muy delicado al reconocer la presencia de librerías nativas.
Después de configurar un NDK de Android en su archivo WORKSPACE, Bazel puede compilar de forma cruzada un .so para Android, como esto:
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 quiere que todo el código de la aplicación java esté dentro del directorio de nivel superior ''WORKSPACE'' (en el repositorio de Tensorflow)
Cuando se libera 0.1.4 (empujándolo ahora) y hemos aplicado algunas correcciones a TensorFlow y Protobuf, puede comenzar a usar el repositorio de TensorFlow como un repositorio remoto. Después de configurarlo en su archivo WORKSPACE, puede consultar las reglas de TensorFlow usando @tensorflow//foo/bar
labels.
git clone --recurse-submodules https://github.com/tensorflow/tensorflow.git
Nota: --recurse-submodules es importante para jalar submodules.
Instala Bazel desde aquí. Bazel es el sistema de compilación principal para TensorFlow. Ahora, edite WORKSPACE, podemos encontrar el archivo WORKSPACE en el directorio raíz de TensorFlow que hemos clonado anteriormente.
# 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)
Como a continuación con nuestra ruta sdk y 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)
Luego construye el archivo .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
Reemplazo de armeabi-v7a con nuestra arquitectura objetivo deseada. La biblioteca estará ubicada en:
bazel-bin/tensorflow/contrib/android/libtensorflow_inference.so
Para construir la contraparte de Java:
bazel build //tensorflow/contrib/android:android_tensorflow_inference_java
Podemos encontrar el archivo JAR en:
bazel-bin/tensorflow/contrib/android/libandroid_tensorflow_inference_java.jar
Ahora tenemos ambos archivos jar y .so. Ya he creado tanto el archivo .so como el archivo jar, que puedes usar directamente desde el project .
Coloque libandroid_tensorflow_inference_java.jar en la carpeta libs y haga clic derecho y agregue como biblioteca.
compile files(''libs/libandroid_tensorflow_inference_java.jar'')
Cree la carpeta jniLibs en el directorio principal y ponga libtensorflow_inference.so en la carpeta jniLibs / armeabi-v7a /.
Ahora podremos llamar a la API de Java TensorFlow.
La API de Java de TensorFlow ha expuesto todos los métodos requeridos a través de una clase TensorFlowInferenceInterface.
Ahora, tenemos que llamar a la API de Java TensorFlow con la ruta del modelo y cargarla.
He escrito un blog completo here .