2018.10.01
TensorFlow ServingでTensorFlowの学習済みモデルをDeployしてみた
こんにちは。次世代システム研究室のT.D.Qです。
今日は、TensorFlowの学習済みモデルを、サーバーで動かすためのTensorFlow Servingを紹介したいと思います。
TensorFlow Servingとは
TensorFlowの学習済みモデルを本番環境で運用することを目的に設計されたモジュールです。一言で言うと、Tensorflowのservableなオブジェクト読み込んで、gRpcでリクエストを受け付けて、実行してくれるとても速いC++で書かれたサーバーです。基本的にはDockerでサーバ構築することが推奨されています。Servingはいくつかの概念がありますが、詳しくは公式ドキュメントのArchitecture overviewをご参照ください。
TensorFlow Servingの導入流れ
TensorFlow Servingを使った機械学習モデルの配信は以下のような流れになります。
①学習済みモデルをエクスポートしてモデルサーバーを起動する
②クライアントからREST APIまたはgRPCでモデルサーバーにリクエストを送る
③モデルのバージョンを追加してモデルサーバーに反映する
開発環境構築
ここでは、MNISTの学習済みモデルを本番環境で利用する場合を例に、TensorFlow Servingの利用方法を説明したいと思います。
DockerでTensorFlowの開発環境を構築するときに一番速いので、この方法を使います。
まず、Dockerをインストールしますが、インストール手順についてはこちらのページが丁寧に説明しているのでご参照ください。
Dockerをインストールした後、下記のコマンドで実行することでGoogleが提供するTensorFlowのDocker Imageを適用し、開発環境(Python3, TensorFlow, TensorBoard, SkLearn, Keras, Jupyter Notebook, Pandas, Scipyなど)を一瞬で構築できます。
docker run -it --rm --name tf -v `pwd`:/notebooks -p 8888:8888 -p 6006:6006 tensorflow/tensorflow:latest-py3
デバッグするため、TensorBoardを起動し、「http://127.0.0.1:6006/」にアクセスするとTensorBoardが表示されるはずです。
docker exec -it tf tensorboard --logdir tf_logs/
TensorFlowモデルを訓練してエクスポートする
分かりやすくするため、今回は「MNIST Softmax Regression TensorFlow model」を使います。TensorFlow Servingを対応するため、このモデルに下記のように設計されます。
①トレーニングの時にパラメータ(epochやversionなど)を指定可能
# Train model print('Training model...') mnist = mnist_input_data.read_data_sets(FLAGS.work_dir, one_hot=True) sess = tf.InteractiveSession() serialized_tf_example = tf.placeholder(tf.string, name='tf_example') feature_configs = {'x': tf.FixedLenFeature(shape=[784], dtype=tf.float32),} tf_example = tf.parse_example(serialized_tf_example, feature_configs) x = tf.identity(tf_example['x'], name='x') # use tf.identity() to assign name y_ = tf.placeholder('float', shape=[None, 10]) w = tf.Variable(tf.zeros([784, 10])) b = tf.Variable(tf.zeros([10])) sess.run(tf.global_variables_initializer()) y = tf.nn.softmax(tf.matmul(x, w) + b, name='y') cross_entropy = -tf.reduce_sum(y_ * tf.log(y)) train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy) values, indices = tf.nn.top_k(y, 10) table = tf.contrib.lookup.index_to_string_table_from_tensor( tf.constant([str(i) for i in range(10)])) prediction_classes = table.lookup(tf.to_int64(indices)) for _ in range(FLAGS.training_iteration): batch = mnist.train.next_batch(50) train_step.run(feed_dict={x: batch[0], y_: batch[1]}) correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1)) accuracy = tf.reduce_mean(tf.cast(correct_prediction, 'float')) print('training accuracy %g' % sess.run( accuracy, feed_dict={ x: mnist.test.images, y_: mnist.test.labels })) print('Done training!')
②トレーニング後、特定の場所に学習済みモデルをエクスポートします
# Export model # WARNING(break-tutorial-inline-code): The following code snippet is # in-lined in tutorials, please update tutorial documents accordingly # whenever code changes. export_path_base = sys.argv[-1] export_path = os.path.join( tf.compat.as_bytes(export_path_base), tf.compat.as_bytes(str(FLAGS.model_version))) print('Exporting trained model to', export_path) builder = tf.saved_model.builder.SavedModelBuilder(export_path)
早速、モデルをトレーニングします。
mnist_saved_model.py [--training_iteration=x] [--model_version=y] export_dir root@31db816c13c7:/notebooks# python mnist_saved_model.py --training_iteration=2000 --model_version=1 models/mnist Training model... Successfully downloaded train-images-idx3-ubyte.gz 9912422 bytes. Extracting /tmp/train-images-idx3-ubyte.gz Successfully downloaded train-labels-idx1-ubyte.gz 28881 bytes. Extracting /tmp/train-labels-idx1-ubyte.gz Successfully downloaded t10k-images-idx3-ubyte.gz 1648877 bytes. Extracting /tmp/t10k-images-idx3-ubyte.gz Successfully downloaded t10k-labels-idx1-ubyte.gz 4542 bytes. Extracting /tmp/t10k-labels-idx1-ubyte.gz 2018-09-30 13:31:40.178536: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA 2018-09-30 13:31:50.335174: W tensorflow/core/framework/allocator.cc:113] Allocation of 31360000 exceeds 10% of system memory. training accuracy 0.9147 Done training! Exporting trained model to b'models/mnist/1' Done exporting!
トレーニングしたモデルを確認します。
root@31db816c13c7:/notebooks# ls -al models/mnist total 0 drwxr-xr-x 4 root root 128 Sep 30 13:31 . drwxr-xr-x 3 root root 96 Sep 30 11:56 .. drwxr-xr-x 4 root root 128 Sep 30 11:56 1 root@31db816c13c7:/notebooks# ll models/mnist/1 total 20 drwxr-xr-x 4 502 dialout 128 Sep 30 11:56 ./ drwxr-xr-x 4 502 dialout 128 Sep 30 13:31 ../ -rw-r--r-- 1 502 dialout 17946 Sep 30 11:56 saved_model.pb drwxr-xr-x 4 502 dialout 128 Sep 30 11:56 variables/
TensorFlow Servingを起動する
まず、Servingサーバをインストールするため、Tensorflow Serving RepoからソースコードをCloneします。
git clone https://github.com/tensorflow/serving cd serving/tensorflow_serving/tools/docker docker build --pull -t test-tensorflow-serving .
Servingサーバ (CPUモードでもGPUでも) 下記の設定があります
・ gRPCが8500ポートを使います
・ REST APIが8501ポートを使います
・ MODEL_NAME変数名が任意設定 (デフォルトモデル名(model)を指定)
・ MODEL_BASE_PATH変数名が任意設定 (デフォルトが/models)
サーバインストール完了したあと、開発PCからトレーニングしたモデルをServingサーバーに展開します。
YINN0529:tensorflow usr0101836$ docker cp models/mnist 35ffbacf7cc5:/home/models/ YINN0529:tensorflow usr0101836$ docker exec -it 35ffbacf7cc5 /bin/bash root@35ffbacf7cc5:/# ll /home/models/mnist/1/ total 20 drwxr-xr-x 4 502 dialout 128 Sep 30 11:56 ./ drwxr-xr-x 4 502 dialout 128 Sep 30 13:31 ../ -rw-r--r-- 1 502 dialout 17946 Sep 30 11:56 saved_model.pb drwxr-xr-x 4 502 dialout 128 Sep 30 11:56 variables/
下記のコマンドでServingサーバを起動します。
YINN0529:serving usr0101836$ docker run -p 8500:8500 \ > --mount type=bind,source=$(pwd)/models/monitored,target=/models/mnist \ > -t --entrypoint=tensorflow_model_server tensorflow/serving --enable_batching \ > --port=8500 --model_name=mnist --model_base_path=/models/mnist & [1] 94804 YINN0529:serving usr0101836$ 2018-09-30 10:08:14.564773: I tensorflow_serving/model_servers/main.cc:157] Building single TensorFlow model file config: model_name: mnist model_base_path: /models/mnist 2018-09-30 10:08:14.584282: I tensorflow_serving/model_servers/server_core.cc:462] Adding/updating models. 2018-09-30 10:08:14.584349: I tensorflow_serving/model_servers/server_core.cc:517] (Re-)adding model: mnist 2018-09-30 10:08:14.695635: I tensorflow_serving/core/basic_manager.cc:739] Successfully reserved resources to load servable {name: mnist version: 1} 2018-09-30 10:08:14.696002: I tensorflow_serving/core/loader_harness.cc:66] Approving load for servable version {name: mnist version: 1} 2018-09-30 10:08:14.696758: I tensorflow_serving/core/loader_harness.cc:74] Loading servable version {name: mnist version: 1} 2018-09-30 10:08:14.697839: I external/org_tensorflow/tensorflow/contrib/session_bundle/bundle_shim.cc:360] Attempting to load native SavedModelBundle in bundle-shim from: /models/mnist/1 2018-09-30 10:08:14.698114: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:31] Reading SavedModel from: /models/mnist/1 2018-09-30 10:08:14.719260: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:54] Reading meta graph with tags { serve } 2018-09-30 10:08:14.722398: I external/org_tensorflow/tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA 2018-09-30 10:08:14.738990: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:113] Restoring SavedModel bundle. 2018-09-30 10:08:14.820425: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:90] Running MainOp on SavedModel bundle. 2018-09-30 10:08:14.862450: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:233] SavedModel load for tags { serve }; Status: success. Took 164460 microseconds. 2018-09-30 10:08:14.862534: I tensorflow_serving/servables/tensorflow/saved_model_bundle_factory.cc:100] Wrapping session to perform batch processing 2018-09-30 10:08:14.862560: I tensorflow_serving/servables/tensorflow/bundle_factory_util.cc:153] Wrapping session to perform batch processing 2018-09-30 10:08:14.863618: I tensorflow_serving/servables/tensorflow/saved_model_warmup.cc:83] No warmup data file found at /models/mnist/1/assets.extra/tf_serving_warmup_requests 2018-09-30 10:08:14.874383: I tensorflow_serving/core/loader_harness.cc:86] Successfully loaded servable version {name: mnist version: 1} 2018-09-30 10:08:14.892834: I tensorflow_serving/model_servers/main.cc:327] Running ModelServer at 0.0.0.0:8500 ...
Dockerコンタイナーのプロセスを確認します。
YINN0529:example usr0101836$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 35ffbacf7cc5 test-tensorflow-serving "/bin/bash" 3 hours ago Up 3 hours 0.0.0.0:8500-8501->8500-8501/tcp determined_bassi 31db816c13c7 tensorflow/tensorflow:latest-py3 "/run_jupyter.sh --a…" 3 hours ago Up 3 hours 0.0.0.0:6006->6006/tcp, 0.0.0.0:8888->8888/tcp tf YINN0529:example usr0101836$
Servingサーバにログインして、サービスを起動します。
root@35ffbacf7cc5:/# cat /home/configs/models.conf model_config_list: { config: { name: "mnist", base_path: "/home/models/mnist", model_platform: "tensorflow", model_version_policy: { all: {} } } } root@35ffbacf7cc5:/# tensorflow_model_server --port=8500 --rest_api_port=8501 --model_config_file=/home/configs/models.conf
ここでServingサーバが問題なく起動できたら、システム構築がほぼ完了となります。
動作確認
動作確認端末で行うため、まず下記のモジュールをインストールします
YINN0529:tensorflow_serving usr0101836$ pip install tensorflow-serving-api
モデルを確認するため、Googleが提供するサンプルクラス(mnist_client)を使います。このスクリプトはgRPCを使ってPredict RequestをServingサーバに送ります。
YINN0529:example usr0101836$ python mnist_client.py --num_tests=100 --server=127.0.0.1:8500 /anaconda3/lib/python3.6/site-packages/h5py/__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`. from ._conv import register_converters as _register_converters Extracting /tmp/train-images-idx3-ubyte.gz Extracting /tmp/train-labels-idx1-ubyte.gz Extracting /tmp/t10k-images-idx3-ubyte.gz Extracting /tmp/t10k-labels-idx1-ubyte.gz .................................................................................................... Inference error rate: 7.000000000000001%
Softmaxモデルの精度が90%前後を期待しているため、推論のエラーレートが7%ということで、トレーニング済みなモデルをServingで正常にロードして実行したことを確認できました。
Servingサーバに他の学習済みモデルをDeployして確認する
別で用意されるIris Classifyモデルをトレーニングした後、Servingサーバの/home/modelsフォルダーにアップロードします。今回は、バージョン1がClassificationモデルで、バージョン2がRegressionモデルとしてDeployします。
root@35ffbacf7cc5:/# ll /home/models/iris/ total 0 drwxr-xr-x 4 root root 128 Sep 30 12:30 ./ drwxr-xr-x 5 root root 160 Sep 30 13:35 ../ drwxr-xr-x 4 root root 128 Sep 30 12:30 1/ drwxr-xr-x 4 root root 128 Sep 30 12:30 2/ root@35ffbacf7cc5:/# cat /home/configs/models.conf model_config_list: { config: { name: "mnist", base_path: "/home/models/mnist", model_platform: "tensorflow", model_version_policy: { all: {} } }, config: { name: "iris", base_path: "/home/models/iris", model_platform: "tensorflow", model_version_policy: { all: {} } } }
REST APIで動作確認します
YINN0529:example usr0101836$ curl -X POST \ > http://localhost:8501/v1/models/iris:classify \ > -H 'cache-control: no-cache' \ > -H 'postman-token: f7fb6e3f-26ba-a742-4ab3-03c953cefaf5' \ > -d '{ > "examples":[ > {"x": [5.1, 3.5, 1.4, 0.2]} > ] > }' { "results": [[["Iris-setosa", 0.872397], ["Iris-versicolor", 0.108623], ["Iris-virginica", 0.0189799]] ] }
YINN0529:example usr0101836$ curl -X POST \ > http://localhost:8501/v1/models/iris/versions/2:predict \ > -d '{ > "signature_name": "predict-iris", > "instances":[ > [5.1, 3.5, 1.4, 0.2] > ] > }' { "predictions": [[0.872397, 0.108623, 0.0189799] ] }
Iris系のモデルも正常にロードされて実行されましたね。
まとめ
今回は、Dockerコンテナを利用して、TensorFlow Servingが動作する環境を作成する手順を説明しました。
また、Pythonで書かれたクライアントプログラムから、TensorFlow Servingに登録した学習済みモデルにMNISTデータを推測させる方法も確認できました。
今回説明した内容は、基本的な作業になりますので、次は自分でCI/CDツールを使って学習済みモデルを自動的にDeployしたり、KubernetesでServingサーバを本番環境に展開してみると良いでしょう。
それでは、また。
次世代システム研究室では、アプリケーション開発や設計を行うリードエンジニアを募集しています。アプリケーション開発者の方、次世代システム研究室にご興味を持って頂ける方がいらっしゃいましたら、ぜひ 募集職種一覧 からご応募をお願いします。
グループ研究開発本部の最新情報をTwitterで配信中です。ぜひフォローください。
Follow @GMO_RD