[PYTHON] J'ai essayé d'héberger un modèle d'apprentissage en profondeur de TensorFlow à l'aide de TensorFlow Serving

introduction

TensorFlow Serving est un système de service de modèle d'apprentissage automatique flexible et hautes performances conçu pour les environnements de production. TensorFlow Serving facilite l'hébergement des modèles créés avec TensorFlow et expose les API.

Consultez la documentation du serveur TensorFlow (https://www.tensorflow.org/tfx/guide/serving) pour plus d'informations.

Cette fois, j'ai utilisé TensorFlow Serving sur AWS EC2 pour héberger un modèle d'apprentissage en profondeur de TensorFlow. À la fin de l'article, je l'essaie également avec Docker.

procédure

Création d'instance EC2

Entrez "Deep Learning AMI" dans la barre de recherche AMI pour rechercher l'AMI que vous souhaitez utiliser. Cette fois, j'ai utilisé "Deep Learning AMI (Ubuntu 18.04) Version 30.0 --ami-0b1b56cbf0f8fcea3". J'ai utilisé "p2.xlarge" comme type d'instance. Le groupe de sécurité est défini de sorte que ssh et http puissent être connectés à partir de l'environnement de développement, et tous les autres paramètres sont conservés par défaut.

Environnement

Connectez-vous à EC2 et créez l'environnement.

~$ ls
LICENSE                README     examples  tools
Nvidia_Cloud_EULA.pdf  anaconda3  src       tutorials

La procédure d'installation est présentée sur le Site officiel.

Tout d'abord, ajoutez l'URI de serveur TensorFlow à sources.list.d.

~$ echo "deb [arch=amd64] http://storage.googleapis.com/tensorflow-serving-apt stable tensorflow-model-server tensorflow-model-server-universal" | sudo tee /etc/apt/sources.list.d/tensorflow-serving.list && \
curl https://storage.googleapis.com/tensorflow-serving-apt/tensorflow-serving.release.pub.gpg | sudo apt-key add -

deb [arch=amd64] http://storage.googleapis.com/tensorflow-serving-apt stable tensorflow-model-server tensorflow-model-server-universal
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  2943  100  2943    0     0  18166      0 --:--:-- --:--:-- --:--:-- 18166
OK

Effectuez l'installation.

~$ sudo apt-get update && apt-get install tensorflow-model-server
~$ tensorflow_model_server --version
TensorFlow ModelServer: 1.15.0-rc2+dev.sha.1ab7d59
TensorFlow Library: 1.15.2

Ceci termine l'installation.

Construction de modèles

De là, nous allons créer un modèle à déployer. Tout d'abord, préparez un répertoire de travail.

~$ mkdir tfexample
~$ cd tfexample

Démarrez jupyter-lab et créez le modèle.

~/tfexample$ jupyter-lab --no-browser --port=8888 --ip=0.0.0.0 --allow-root

...
http://127.0.0.1:8888/?token=b92a7ceefb20c7ab3e475474dbde66a771870de1d8f5bd70
...

Puisqu'il y a un endroit où l'URL est affichée dans la sortie standard, accédez en réécrivant la partie de 127.0.0.1 à l'adresse IP de l'instance.

Une fois le laboratoire jupyer démarré, sélectionnez le noyau conda_tensorflow2_py36 et ouvrez le notebook. Renommez-le en tfmodel.ipynb.

Cette fois, je vais faire un modèle avec Fashionmnist.

tfmodel.ipynb


import sys
import tensorflow as tf
from tensorflow import keras
import numpy as np
import matplotlib.pyplot as plt
import os
import tempfile

print('TensorFlow version: {}'.format(tf.__version__))
# TensorFlow version: 2.1.0

tfmodel.ipynb


fashion_mnist = keras.datasets.fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()

# scale the values to 0.0 to 1.0
train_images = train_images / 255.0
test_images = test_images / 255.0

# reshape for feeding into the model
train_images = train_images.reshape(train_images.shape[0], 28, 28, 1)
test_images = test_images.reshape(test_images.shape[0], 28, 28, 1)

class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']

print('\ntrain_images.shape: {}, of {}'.format(train_images.shape, train_images.dtype))
print('test_images.shape: {}, of {}'.format(test_images.shape, test_images.dtype))
# train_images.shape: (60000, 28, 28, 1), of float64
# test_images.shape: (10000, 28, 28, 1), of float64

tfmodel.ipynb


model = keras.Sequential([
  keras.layers.Conv2D(input_shape=(28,28,1), filters=8, kernel_size=3, 
                      strides=2, activation='relu', name='Conv1'),
  keras.layers.Flatten(),
  keras.layers.Dense(10, activation=tf.nn.softmax, name='Softmax')
])
model.summary()

testing = False
epochs = 5

model.compile(optimizer='adam', 
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])
model.fit(train_images, train_labels, epochs=epochs)

test_loss, test_acc = model.evaluate(test_images, test_labels)
print('\nTest accuracy: {}'.format(test_acc))

# Model: "sequential"
# _________________________________________________________________
# Layer (type)                 Output Shape              Param #   
# =================================================================
# Conv1 (Conv2D)               (None, 13, 13, 8)         80        
# _________________________________________________________________
# flatten (Flatten)            (None, 1352)              0         
# _________________________________________________________________
# Softmax (Dense)              (None, 10)                13530     
# =================================================================
# Total params: 13,610
# Trainable params: 13,610
# Non-trainable params: 0
# _________________________________________________________________
# Train on 60000 samples
# Epoch 1/5
# 60000/60000 [==============================] - 46s 770us/sample - loss: 0.5398 - accuracy: 0.8182
# Epoch 2/5
# 60000/60000 [==============================] - 5s 76us/sample - loss: 0.3849 - accuracy: 0.8643
# Epoch 3/5
# 60000/60000 [==============================] - 5s 76us/sample - loss: 0.3513 - accuracy: 0.8751
# Epoch 4/5
# 60000/60000 [==============================] - 5s 76us/sample - loss: 0.3329 - accuracy: 0.8820
# Epoch 5/5
# 60000/60000 [==============================] - 5s 76us/sample - loss: 0.3204 - accuracy: 0.8847
# 10000/10000 [==============================] - 1s 78us/sample - loss: 0.3475 - accuracy: 0.8779

# Test accuracy: 0.8779000043869019

tfmodel.ipynb


MODEL_DIR = tempfile.gettempdir()
version = 1
export_path = os.path.join(MODEL_DIR, str(version))
print('export_path = {}\n'.format(export_path))

tf.keras.models.save_model(
    model,
    export_path,
    overwrite=True,
    include_optimizer=True,
    save_format=None,
    signatures=None,
    options=None
)

print('\nSaved model:')
!ls -l {export_path}

# export_path = /tmp/1

# WARNING:tensorflow:From /home/ubuntu/anaconda3/envs/tensorflow2_p36/lib/python3.6/site-packages/tensorflow_core/python/ops/resource_variable_ops.py:1786: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.
# Instructions for updating:
# If using Keras pass *_constraint arguments to layers.
# INFO:tensorflow:Assets written to: /tmp/1/assets

# Saved model:
# total 84
# drwxr-xr-x 2 ubuntu ubuntu  4096 Jul 17 10:49 assets
# -rw-rw-r-- 1 ubuntu ubuntu 74970 Jul 17 10:49 saved_model.pb
# drwxr-xr-x 2 ubuntu ubuntu  4096 Jul 17 10:49 variables

La destination de sauvegarde du modèle a été créée par le module tempfile. Cette fois, le modèle est stocké dans / tmp / 1.

Hôte modèle

Ouvrez un autre terminal, connectez-vous à l'instance et démarrez le serveur.

~$ export MODEL_DIR=/tmp
~$ tensorflow_model_server \
  --rest_api_port=8501 \
  --model_name=fashion_model \
  --model_base_path="${MODEL_DIR}"

Il semble que la structure devrait être telle qu'il y ait un répertoire indiquant la version sous model_base_path, et le modèle est sauvegardé sous celui-ci.

model_base_path/
 ├ 1/
 │ ├ assets/
 │ ├ variables/
 │ └ saved_model.pb
 ├ 2/
│ ├ (omis ci-dessous)

Je vais lancer une demande et la vérifier. Revenez à votre ordinateur portable et faites une demande.

tfmodel.ipynb


def show(idx, title):
    plt.figure()
    plt.imshow(test_images[idx].reshape(28,28), cmap = "gray")
    plt.axis('off')
    plt.title('\n\n{}'.format(title), fontdict={'size': 16})

tfmodel.ipynb


import json

data = json.dumps({"signature_name": "serving_default", "instances": test_images[0:3].tolist()})
print('Data: {} ... {}'.format(data[:50], data[len(data)-52:]))
# Data: {"signature_name": "serving_default", "instances": ...  [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0]]]]}

tfmodel.ipynb


import requests

headers = {"content-type": "application/json"}
json_response = requests.post('http://localhost:8501/v1/models/fashion_model:predict', data=data, headers=headers)
predictions = json.loads(json_response.text)['predictions']

show(0, 'The model thought this was a {} (class {}), and it was actually a {} (class {})'.format(
  class_names[np.argmax(predictions[0])], np.argmax(predictions[0]), class_names[test_labels[0]], test_labels[0]))
スクリーンショット 2020-07-17 22.02.44.png

Envoyez les données au format json par POST. J'ai défini les données pour la clé ʻinstances`, mais comme je la prédis par lots, je dois faire attention à la forme.

En passant, le contenu des «prédictions» est le suivant.

predictions[0]

# [7.71279588e-07,
#  4.52205953e-08,
#  5.55571035e-07,
#  1.59779923e-08,
#  2.27421737e-07,
#  0.00600787532,
#  8.29056205e-07,
#  0.0466650613,
#  0.00145569211,
#  0.945868969]

Les probabilités pour chaque classe sont stockées dans la liste. C'est la même sortie que le code suivant.

model.predict(test_images[0:3]).tolist()[0]

Hébergement avec docker

~$ docker --version
Docker version 19.03.11, build 42e35e61f3
~$ docker pull tensorflow/serving
~$ docker run -d -t --rm -p 8501:8501 -v "/tmp:/models/fashion_model" -e MODEL_NAME=fashion_model tensorflow/serving

Les points d'entrée sont les suivants. Le port de l'API RESTful est 8501, le port gRPC est 8500 et le model_base_path est $ {MODEL_BASE_PATH} / $ {MODEL_NAME}.

tensorflow_model_server --port=8500 --rest_api_port=8501 \
  --model_name=${MODEL_NAME} --model_base_path=${MODEL_BASE_PATH}/${MODEL_NAME}

Le fichier du point d'entrée est stocké dans / usr / bin / tf_serving_entrypoint.sh et contient en fait le code suivant:

#!/bin/bash 

tensorflow_model_server --port=8500 --rest_api_port=8501 --model_name=${MODEL_NAME} --model_base_path=${MODEL_BASE_PATH}/${MODEL_NAME} "$@"

Par conséquent, lors de l'utilisation de docker, tout ce que vous avez à faire est de monter le chemin de stockage du modèle de l'hôte sur model_base_path de docker.

Autres notes

Recommended Posts

J'ai essayé d'héberger un modèle d'apprentissage en profondeur de TensorFlow à l'aide de TensorFlow Serving
J'ai essayé d'héberger le modèle d'apprentissage en profondeur de Pytorch avec TorchServe sur Amazon SageMaker
J'ai essayé d'héberger un exemple de modèle de Pytorch en utilisant TorchServe
J'ai essayé l'apprentissage en profondeur avec Theano
J'ai essayé d'écrire dans un modèle de langage profondément appris
J'ai essayé de jouer au jeu ○ ✕ en utilisant TensorFlow
J'ai essayé le deep learning
J'ai créé un jeu ○ ✕ avec TensorFlow
J'ai créé un classificateur de visage Dir en gray en utilisant TensorFlow --⑦ Modèle d'apprentissage
J'ai essayé d'utiliser magenta / TensorFlow
J'ai essayé de refactoriser le modèle CNN de TensorFlow en utilisant TF-Slim
J'ai essayé d'utiliser Tensorboard, un outil de visualisation pour l'apprentissage automatique
J'ai fait un modèle VGG16 en utilisant TensorFlow (en chemin)
J'ai essayé l'apprentissage par renforcement avec PyBrain
Créer un modèle d'apprentissage à l'aide de MNIST
J'ai essayé de dessiner une ligne en utilisant une tortue
Modèle de reconnaissance d'image utilisant l'apprentissage profond en 2016
Prévision du cours des actions à l'aide du Deep Learning (TensorFlow)
J'ai essayé de classer le texte en utilisant TensorFlow
J'ai essayé d'utiliser pipenv, alors prenez note
[ML-Aents] J'ai essayé l'apprentissage automatique en utilisant TensorFlow de Unity et Python (compatible v0.11β)
J'ai créé un classificateur de visage Dir en gray en utilisant TensorFlow --⑧ Exécution d'apprentissage
J'ai essayé l'histoire courante de l'utilisation du Deep Learning pour prédire la moyenne Nikkei
J'ai essayé l'histoire courante de prédire la moyenne Nikkei à l'aide du Deep Learning (backtest)
Une histoire sur l'apprentissage automatique simple avec TensorFlow
Un amateur a essayé le Deep Learning avec Caffe (Introduction)
Un amateur a essayé le Deep Learning en utilisant Caffe (Practice)
Prévision du cours des actions à l'aide du Deep Learning (TensorFlow) - Partie 2
J'ai essayé d'utiliser Pythonect, un langage de programmation de flux de données.
J'ai essayé de lire un fichier CSV en utilisant Python
Un amateur a essayé le Deep Learning avec Caffe (Vue d'ensemble)
J'ai essayé d'utiliser la base de données (sqlite3) avec kivy
J'ai installé le framework Deep Learning Chainer
Créez une API REST à l'aide du modèle appris dans Lobe et TensorFlow Serving.
J'ai essayé d'extraire le dessin au trait de l'image avec Deep Learning
J'ai essayé d'exécuter le didacticiel de détection d'objets en utilisant le dernier algorithme d'apprentissage en profondeur
J'ai essayé d'implémenter diverses méthodes d'apprentissage automatique (modèle de prédiction) en utilisant scicit-learn
J'ai essayé d'utiliser paramétré
J'ai essayé d'utiliser argparse
J'ai essayé d'utiliser la mimesis
J'ai essayé d'utiliser anytree
J'ai essayé d'utiliser Summpy
J'ai essayé d'utiliser coturn
J'ai essayé d'utiliser Pipenv
J'ai essayé d'utiliser matplotlib
J'ai essayé d'utiliser "Anvil".
J'ai essayé d'utiliser Hubot
J'ai essayé d'utiliser ESPCN
J'ai essayé d'utiliser openpyxl
J'ai essayé d'utiliser Ipython
J'ai essayé d'utiliser PyCaret
J'ai essayé d'utiliser cron
J'ai essayé d'utiliser ngrok
J'ai essayé d'utiliser face_recognition
J'ai essayé d'utiliser Jupyter
J'ai essayé d'utiliser doctest