Sur la base du tutoriel TensorFlow (reconnaissance d'image des données d'images manuscrites), j'ai écrit les données réseau de Deep Learning et créé une démo de reconnaissance de l'écriture manuscrite sur Android.
En vous basant sur le modèle «MNIST For ML Beginners» du didacticiel TensorFlow, commencez par écrire les données d'entraînement en Python sur votre PC.
"MNIST For ML Beginners" https://www.tensorflow.org/versions/master/tutorials/mnist/beginners/index.html
Sur la base du tutoriel ici, j'ai modifié le script d'exportation des données graphiques.
https://github.com/miyosuda/TensorFlowAndroidMNIST/blob/master/trainer-script/beginner.py
Afin d'exporter des données de réseau, il est nécessaire d'exporter les informations de graphe et les données de tenseur (contenu appris) dans Variable, mais pour le moment, TensorFlow peut enregistrer les informations de graphe et la Variable ensemble. Je n'arrivais pas à le faire.
Donc, après avoir appris, évaluez le contenu de Viriables, convertissez-le une fois en ndarray,
# Store variable
_W = W.eval(sess)
_b = b.eval(sess)
J'ai converti le ndarray en Constant et l'ai utilisé comme substitut aux Variables pour reconstruire le graphique et exporté le graphique et les données d'entraînement ensemble.
#Regenerate graph g_2 = tf.Graph() with g_2.as_default():
x_2 = tf.placeholder("float", [None, 784], name="input")
Remplacer # Variables par Constante W_2 = tf.constant(_W, name="constant_W") b_2 = tf.constant(_b, name="constant_b")
y_2 = tf.nn.softmax(tf.matmul(x_2, W_2) + b_2, name="output")
sess_2 = tf.Session()
init_2 = tf.initialize_all_variables()
sess_2.run(init_2)
graph_def = g_2.as_graph_def()
tf.train.write_graph(graph_def, './tmp/beginner-export',
'beginner-graph.pb', as_text=False)
Afin de l'appeler du côté Android, j'ai nommé les nœuds d'entrée et de sortie comme «entrée» et «sortie», respectivement.
Il n'a fallu que quelques secondes pour entraîner et exporter ce modèle.
La démo Android incluse à l'origine dans TensorFlow ne pouvait être construite que dans l'environnement Bazel, j'ai donc créé un environnement dans lequel les applications Android peuvent être créées en utilisant uniquement Android Studio et NDK.
J'ai enregistré le fichier de bibliothèque (fichier .a) qui peut être créé lors de la construction de l'exemple Android de TensorFlow avec Bazel afin qu'il ne puisse être construit qu'avec NDK.
https://github.com/miyosuda/TensorFlowAndroidMNIST/tree/master/jni-build/jni
Android.mk ressemble à ceci.
Makefile
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
TENSORFLOW_CFLAGS := -frtti \
-fstack-protector-strong \
-fpic \
-ffunction-sections \
-funwind-tables \
-no-canonical-prefixes \
'-march=armv7-a' \
'-mfpu=vfpv3-d16' \
'-mfloat-abi=softfp' \
'-std=c++11' '-mfpu=neon' -O2 \
TENSORFLOW_SRC_FILES := ./tensorflow_jni.cc \
./jni_utils.cc \
LOCAL_MODULE := tensorflow_mnist
LOCAL_ARM_MODE := arm
LOCAL_SRC_FILES := $(TENSORFLOW_SRC_FILES)
LOCAL_CFLAGS := $(TENSORFLOW_CFLAGS)
LOCAL_LDLIBS := \
-Wl,-whole-archive \
$(LOCAL_PATH)/libs/$(TARGET_ARCH_ABI)/libandroid_tensorflow_lib.a \
$(LOCAL_PATH)/libs/$(TARGET_ARCH_ABI)/libre2.a \
$(LOCAL_PATH)/libs/$(TARGET_ARCH_ABI)/libprotos_all_cc.a \
$(LOCAL_PATH)/libs/$(TARGET_ARCH_ABI)/libprotobuf.a \
$(LOCAL_PATH)/libs/$(TARGET_ARCH_ABI)/libprotobuf_lite.a \
-Wl,-no-whole-archive \
$(NDK_ROOT)/sources/cxx-stl/gnu-libstdc++/4.9/libs/$(TARGET_ARCH_ABI)/libgnustl_static.a \
$(NDK_ROOT)/sources/cxx-stl/gnu-libstdc++/4.9/libs/$(TARGET_ARCH_ABI)/libsupc++.a \
-llog -landroid -lm -ljnigraphics -pthread -no-canonical-prefixes '-march=armv7-a' -Wl,--fix-cortex-a8 -Wl,-S \
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include $(LOCAL_PATH)/genfiles $(LOCAL_PATH)/include/third_party/eigen3
NDK_MODULE_PATH := $(call my-dir)
include $(BUILD_SHARED_LIBRARY)
Si l'option du compilateur et l'option de l'éditeur de liens n'étaient pas définies comme ci-dessus, les données d'entraînement (données des tampons de protocole) ne pouvaient pas être lues correctement, même si la génération avait réussi.
Préparez des données de pixels manuscrites 28x28 du côté Java, transmettez-les au côté c ++ avec JNI et saisissez-les dans le graphique créé en fonction des données du graphique.
https://github.com/miyosuda/TensorFlowAndroidMNIST/blob/master/jni-build/jni/tensorflow_jni.cc
J'ai pu le reconnaître en toute sécurité.
Avec le modèle ci-dessus, le taux de reconnaissance est d'environ 91%, je l'ai donc remplacé par un modèle utilisant le Deep Learning (taux de reconnaissance 99,2%) dans "Deep MNIST for Experts" de TensorFlow.
"Deep MNIST for Experts" https://www.tensorflow.org/versions/master/tutorials/mnist/pros/index.html
Script d'exportation des données d'entraînement https://github.com/miyosuda/TensorFlowAndroidMNIST/blob/master/trainer-script/expert.py
Si le nœud DropOut est inclus, une erreur s'est produite lors de l'exécution du côté Android, et comme le nœud DropOut n'est à l'origine nécessaire que pour l'apprentissage, je l'ai supprimé du graphique lors de l'exportation.
Il a fallu environ une heure pour étudier dans mon environnement (MacBook Pro).
Étant donné que les noms du nœud d'entrée et du nœud de sortie sont les mêmes, après l'exportation, tout le code côté Android peut être exécuté tel quel en remplaçant simplement les données d'entraînement.
Lorsque j'ai essayé la reconnaissance de l'écriture manuscrite, j'ai pu confirmer qu'elle reconnaît assez précisément les nombres de 0 à 9.
Cliquez ici pour l'ensemble de sources ci-dessus https://github.com/miyosuda/TensorFlowAndroidMNIST
Recommended Posts