├── README.md ├── eval.py ├── export.py ├── modeling.py ├── serving_flask.py └── train.py /README.md: -------------------------------------------------------------------------------- 1 | # Process from training with estimator to serving with flask 2 | 3 | * Dataset: MNIST dataset from *Keras* 4 | * Training Method : Tensorflow Estimator 5 | * One of the MNIST datasets is randomly selected to show the predicted result and label. 6 | 7 | ## File explaination 8 | 9 | * modeling.py : make model for tensorflow estimator 10 | * train.py : tensorflow training process 11 | * eval.py : evaluate tensorflow estimator model based on train.py 12 | * export.py : export freeze model from model made by train.py 13 | * serving_flask.py : serving freeze model with flask method 14 | 15 | ## Requirements 16 | 17 | * tensorflow==1.14.0 18 | * numpy 19 | * flask 20 | * flask-restful 21 | 22 | ## Command line 23 | 24 | ``` 25 | python train.py ## training 26 | python eval.py ## evaluate 27 | python export.py ## export model 28 | python serving_flask.py ## serving by flask, you have to edit line 17(export file path) 29 | ``` 30 | 31 | ## Serving and Check by requests module 32 | 33 | ### Serving 34 | ``` 35 | (xxx) xxx@xxx:~/flask-tensorflow$ python serving_flask.py 36 | WARNING: Logging before flag parsing goes to stderr. 37 | W0831 03:19:47.895947 139689095231296 deprecation_wrapper.py:119] From serving_flask.py:19: The name tf.get_default_graph is deprecated. Please use tf.compat.v1.get_default_graph instead. 38 | 39 | W0831 03:19:47.904812 139689095231296 deprecation_wrapper.py:119] From serving_flask.py:20: The name tf.Session is deprecated. Please use tf.compat.v1.Session instead. 40 | ... 41 | ... 42 | XLA_FLAGS=--xla_hlo_profile. 43 | * Serving Flask app "serving_flask" (lazy loading) 44 | * Environment: production 45 | WARNING: This is a development server. Do not use it in a production deployment. 46 | Use a production WSGI server instead. 47 | * Debug mode: off 48 | I0831 03:19:48.059808 139689095231296 _internal.py:122] * Running on http://0.0.0.0:3000/ (Press CTRL+C to quit) 49 | I0831 03:20:00.875686 139682033678080 _internal.py:122] 127.0.0.1 - - [31/Aug/2019 03:20:00] "GET /api/test HTTP/1.1" 200 - 50 | ``` 51 | 52 | ### Check 53 | ``` 54 | Python 3.6.8 |Anaconda, Inc.| (default, Dec 30 2018, 01:22:34) 55 | [GCC 7.3.0] on linux 56 | Type "help", "copyright", "credits" or "license" for more information. 57 | >>> import requests 58 | >>> res = requests.get('http://0.0.0.0:3000/api/test') 59 | >>> print(res.json()) 60 | {'predict': [3], 'answer': 3} 61 | ``` 62 | -------------------------------------------------------------------------------- /eval.py: -------------------------------------------------------------------------------- 1 | import modeling 2 | 3 | import tensorflow as tf 4 | import numpy as np 5 | 6 | ((train_data, train_labels), 7 | (eval_data, eval_labels)) = tf.keras.datasets.mnist.load_data() 8 | 9 | eval_data = eval_data/np.float32(255) 10 | eval_labels = eval_labels.astype(np.int32) # not required 11 | 12 | mnist_classifier = tf.estimator.Estimator( 13 | model_fn=modeling.cnn_model_fn, model_dir='tmp/mnist_convnet_model') 14 | 15 | eval_input_fn = tf.estimator.inputs.numpy_input_fn( 16 | x={'x': eval_data}, 17 | y=eval_labels, 18 | num_epochs=1, 19 | shuffle=False) 20 | 21 | eval_results = mnist_classifier.evaluate(input_fn=eval_input_fn) 22 | print(eval_results) -------------------------------------------------------------------------------- /export.py: -------------------------------------------------------------------------------- 1 | import modeling 2 | 3 | import tensorflow as tf 4 | import numpy as np 5 | 6 | mnist_classifier = tf.estimator.Estimator( 7 | model_fn=modeling.cnn_model_fn, model_dir='tmp/mnist_convnet_model') 8 | 9 | def serving_input_fn(): 10 | receiver_tensors = { 11 | 'image': tf.placeholder(tf.float32, [None, 784], name='image')} 12 | features = { 13 | 'x': receiver_tensors['image']} 14 | return tf.estimator.export.ServingInputReceiver( 15 | receiver_tensors=receiver_tensors, 16 | features=features) 17 | 18 | mnist_classifier.export_savedmodel('export/mnist_convnet_model', serving_input_fn) -------------------------------------------------------------------------------- /modeling.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | 4 | tf.logging.set_verbosity(tf.logging.INFO) 5 | 6 | def cnn_model_fn(features, labels, mode): 7 | 8 | input_layer = tf.reshape(features['x'], [-1, 28, 28, 1], name='input_layer') 9 | print(input_layer) 10 | conv1 = tf.layers.conv2d(inputs=input_layer, filters=32, kernel_size=[5, 5], padding='same', activation=tf.nn.relu, name='conv1') 11 | print(conv1) 12 | conv2 = tf.layers.conv2d(inputs=conv1, filters=32, kernel_size=[5, 5], padding='same', activation=tf.nn.relu, name='conv2') 13 | print(conv2) 14 | flat = tf.layers.flatten(inputs=conv2, name='flat') 15 | print(flat) 16 | dense1 = tf.layers.dense(inputs=flat, units=1024, activation=tf.nn.relu, name='dense1') 17 | print(dense1) 18 | predict = tf.layers.dense(inputs=dense1, units=10, activation=tf.nn.softmax, name='predict') 19 | print(predict) 20 | 21 | predictions = { 22 | 'classes': tf.argmax(input=predict, axis=1), 23 | 'probabilities': predict} 24 | 25 | if mode == tf.estimator.ModeKeys.PREDICT: 26 | return tf.estimator.EstimatorSpec(mode=mode, predictions=predictions) 27 | 28 | answer = tf.one_hot(labels, 10) 29 | loss = tf.reduce_mean(-answer * tf.log(predict + 1e-8)) 30 | accuracy = tf.metrics.accuracy( 31 | labels=labels, predictions=predictions['classes']) 32 | 33 | tf.summary.scalar('loss', loss) 34 | tf.summary.scalar('accuracy', accuracy[1]) 35 | 36 | if mode == tf.estimator.ModeKeys.TRAIN: 37 | optimizer = tf.train.AdamOptimizer(learning_rate=0.0001) 38 | train_op = optimizer.minimize(loss=loss, global_step=tf.train.get_global_step()) 39 | return tf.estimator.EstimatorSpec(mode=mode, loss=loss, train_op=train_op) 40 | 41 | eval_metric_ops = { 42 | 'accuracy': tf.metrics.accuracy( 43 | labels=labels, predictions=predictions['classes'])} 44 | 45 | return tf.estimator.EstimatorSpec( 46 | mode=mode, loss=loss, eval_metric_ops=eval_metric_ops) -------------------------------------------------------------------------------- /serving_flask.py: -------------------------------------------------------------------------------- 1 | import flask 2 | import flask_restful 3 | 4 | import tensorflow as tf 5 | import numpy as np 6 | 7 | from tensorflow.python.saved_model import tag_constants 8 | 9 | ## read data 10 | ((train_data, train_labels), 11 | (eval_data, eval_labels)) = tf.keras.datasets.mnist.load_data() 12 | 13 | eval_data = eval_data/np.float32(255) 14 | eval_labels = eval_labels.astype(np.int32) # not required 15 | 16 | ## load exported model 17 | export_dir = 'export/mnist_convnet_model/1567154280' 18 | 19 | graph = tf.get_default_graph() 20 | sess = tf.Session(graph=graph) 21 | 22 | tf.saved_model.loader.load(sess, [tag_constants.SERVING], export_dir) 23 | 24 | ## get_tensor_by_name 25 | # show all name of tensor 26 | # list_of_tuples = [op.values() for op in graph.get_operations()] 27 | tensor_output_ids = graph.get_tensor_by_name('predict/Softmax:0') 28 | tensor_input_ids = graph.get_tensor_by_name('image:0') 29 | 30 | ## flask server 31 | app = flask.Flask(__name__) 32 | api = flask_restful.Api(app) 33 | 34 | class Test(flask_restful.Resource): 35 | def get(self): 36 | 37 | random_index = np.random.choice(eval_data.shape[0]) 38 | test_data = eval_data[random_index] 39 | test_data = np.reshape(test_data, [784]) 40 | test_answer = eval_labels[random_index] 41 | result = sess.run(tensor_output_ids, feed_dict={ 42 | tensor_input_ids: [test_data]}) 43 | 44 | return { 45 | # 'data': test_data.tolist(), 46 | 'predict': np.argmax(result, axis=1).tolist(), 47 | 'answer': test_answer.tolist() 48 | } 49 | 50 | api.add_resource(Test, '/api/test') 51 | 52 | if __name__ == '__main__': 53 | app.run(host='0.0.0.0', port=3000) -------------------------------------------------------------------------------- /train.py: -------------------------------------------------------------------------------- 1 | import modeling 2 | 3 | import tensorflow as tf 4 | import numpy as np 5 | 6 | ((train_data, train_labels), 7 | (eval_data, eval_labels)) = tf.keras.datasets.mnist.load_data() 8 | 9 | train_data = train_data/np.float32(255) 10 | train_labels = train_labels.astype(np.int32) # not required 11 | 12 | run_config = tf.estimator.RunConfig( 13 | save_checkpoints_steps=1000) 14 | 15 | mnist_classifier = tf.estimator.Estimator( 16 | model_fn=modeling.cnn_model_fn, model_dir='tmp/mnist_convnet_model', 17 | config=run_config) 18 | 19 | train_input_fn = tf.estimator.inputs.numpy_input_fn( 20 | x={'x': train_data}, 21 | y=train_labels, 22 | batch_size=100, 23 | num_epochs=None, 24 | shuffle=True) 25 | 26 | mnist_classifier.train( 27 | input_fn=train_input_fn) --------------------------------------------------------------------------------