#!/usr/bin/env python # coding: utf-8 # In[4]: from IPython.core.display import HTML HTML(""" """) from matplotlib import pyplot as plt get_ipython().run_line_magic('matplotlib', 'inline') import numpy as np # ![](images/tensorflow.jpg) # # ![](https://www.android.com/static/2016/img/share/andy-lg.png) # ![](images/android-tensorflow-app-structure_2.png) # ![](images/android_tensorflow_classifier_results.jpg) # ![](images/example.png) # ![](images/mnist.jpeg) # # Классическая задача распознавания рукописных цифр на основе набора данных [MNIST](http://yann.lecun.com/exdb/mnist/) # In[12]: from model import data x_train, y_train, x_test, y_test = data.load_data() plt.imshow(x_train[0].reshape((28,28)), cmap='gray') # In[53]: import numpy as np from keras.datasets import mnist from keras.utils import to_categorical def load_data(flatten=True): """ Load MNIST dataset, do train-test split, convert data to the necessary format :return: """ if flatten: reshape = _flatten else: reshape = _square (x_train, y_train), (x_test, y_test) = mnist.load_data() x_train = reshape(x_train) x_test = reshape(x_test) x_train = x_train.astype('float32') x_test = x_test.astype('float32') x_train /= 255 x_test /= 255 y_train = to_categorical(y_train, 10) y_test = to_categorical(y_test, 10) return x_train, y_train, x_test, y_test def _flatten(x: np.ndarray) -> np.ndarray: return x.reshape(x.shape[0], 28 * 28) def _square(x: np.ndarray) -> np.ndarray: return x.reshape(x.shape[0], 28, 28, 1) # # Что используем # # - [TensorFlow backend](https://www.tensorflow.org/) # - [Keras](https://keras.io/) # - Android SDK > 23 # - [org.tensorflow:tensorflow-android:1.3.0](https://www.tensorflow.org/mobile/android_build) # In[57]: get_ipython().system('cat model/requirements.txt') # # 1. Neural Network # # Простейшая однослойная нейросеть # ![](images/one_layer.png) # In[44]: import keras keras.backend.clear_session() tf.reset_default_graph() # In[45]: from keras import metrics, Sequential from keras.layers import Dense model = Sequential(layers=[ Dense(10, activation='softmax', input_shape=(784,)) ]) model.summary() # In[46]: from keras.layers import K from keras.optimizers import SGD model.compile(loss=K.categorical_crossentropy, optimizer=SGD(), metrics=[metrics.categorical_accuracy]) # In[47]: model.fit(x_train, y_train, batch_size=128, epochs=10, validation_data=(x_test, y_test)) # # Многослойная нейросеть # ![](images/deep_neural_network.png) # In[48]: keras.backend.clear_session() tf.reset_default_graph() model = Sequential(layers=[ Dense(200, activation='relu', input_shape=(784,)), Dense(10, activation='softmax') ]) model.summary() # In[50]: from keras.callbacks import TensorBoard model.compile(loss=K.categorical_crossentropy, optimizer=SGD(), metrics=[metrics.categorical_accuracy]) model.fit(x_train, y_train, batch_size=128, epochs=10, validation_data=(x_test, y_test), callbacks=[TensorBoard(log_dir='/tmp/tensorflow/dnn_jup')]) # # Tensorboard # ![](images/tensorboard_graph.png) # ![](images/tensorboard_scalars.png) # # Экспорт модели # - pbtxt # - chkp # - pb # - **optimal pb** for android # - ... # In[51]: from model import exporter exporter.export_model(tf.train.Saver(), input_names=['dense_1_input'], output_name='dense_2/Softmax', model_name="dnn_jup") # In[52]: def export_model(saver: tf.train.Saver, input_names: list, output_name: str, model_name: str): """ You can find node names by using debugger: just connect it right after model is created and look for nodes in the inspec :param saver: :param input_names: :param output_name: :param model_name: :return: """ os.makedirs("./out", exist_ok=True) tf.train.write_graph(K.get_session().graph_def, 'out', model_name + '_graph.pbtxt') saver.save(K.get_session(), 'out/' + model_name + '.chkp') # pbtxt is human readable representation of the graph freeze_graph.freeze_graph('out/' + model_name + '_graph.pbtxt', None, False, 'out/' + model_name + '.chkp', output_name, "save/restore_all", "save/Const:0", 'out/frozen_' + model_name + '.pb', True, "") input_graph_def = tf.GraphDef() with tf.gfile.Open('out/frozen_' + model_name + '.pb', "rb") as f: input_graph_def.ParseFromString(f.read()) # optimization of the graph so we can use it in the android app output_graph_def = optimize_for_inference_lib.optimize_for_inference( input_graph_def, input_names, [output_name], tf.float32.as_datatype_enum) # This is archived optimal graph in the protobuf format we'll use in our android App. with tf.gfile.FastGFile('out/opt_' + model_name + '.pb', "wb") as f: f.write(output_graph_def.SerializeToString()) print("graph saved!") # In[58]: get_ipython().system('ls out/') # # Свёрточная нейосеть # ![](images/common_cnn_design.jpg) # ![](images/conv_layers.png) # In[60]: from keras.layers import Conv2D, MaxPooling2D from keras.layers import Flatten # In[65]: keras.backend.clear_session() tf.reset_default_graph() model = Sequential() model.add(Conv2D(filters=16, kernel_size=5, strides=1, padding='same', activation='relu', input_shape=[28, 28, 1])) # 28*28*64 model.add(MaxPooling2D(pool_size=2, strides=2, padding='same')) # 14*14*64 model.add(Conv2D(filters=32, kernel_size=4, strides=1, padding='same', activation='relu')) # 14*14*128 model.add(MaxPooling2D(pool_size=2, strides=2, padding='same')) # 7*7*128 model.add(Conv2D(filters=64, kernel_size=3, strides=1, padding='same', activation='relu')) # 7*7*256 model.add(MaxPooling2D(pool_size=2, strides=2, padding='same')) # 4*4*256 model.add(Flatten()) model.add(Dense(64 * 4, activation='relu')) model.add(Dense(10, activation='softmax')) # In[67]: x_train, y_train, x_test, y_test = data.load_data(flatten=False) # In[69]: get_ipython().system('rm -rf /tmp/tensorflow/conv_jup') from keras.optimizers import Adam model.compile(loss=K.categorical_crossentropy, optimizer=Adam(), metrics=[metrics.categorical_accuracy]) model.fit(x_train, y_train, batch_size=128, epochs=1, validation_data=(x_test, y_test), callbacks=[TensorBoard(log_dir='/tmp/tensorflow/conv_jup')]) # In[ ]: exporter.export_model(tf.train.Saver(), input_names=['conv2d_1_input'], output_name='dense_2/Softmax', model_name="conv_jup") # # 2. Android # ![](images/example.png) # # 3. Интеграция # ```groovy # implementation 'org.tensorflow:tensorflow-android:1.3.0' # ``` # ```kotlin # import org.senior_sigan.digits.views.DrawView # import org.senior_sigan.digits.ml.models.DigitsClassifierFlatten // for DNN # import org.senior_sigan.digits.ml.models.DigitsClassifierSquare // for Conv # ``` # ```kotlin # // somewhere in another thread load the model # val clf = DigitsClassifierFlatten( # assetManager=assets, # modelPath="dnn.pb", # inputSize=28, # inputName="dense_1_input", # outputName="dense_2/Softmax", # name="dnn") # # // somewhere on UI thread # val drawView = find(R.id.draw) # # // somewhere on another thread # val pred = clf.predict(drawView.pixelData) # # Log.i("Dnn", "${pred.label} ${pred.proba}") # # ```