[PYTHON] Ich habe versucht, ein Deep-Learning-Modell von TensorFlow mit TensorFlow Serving zu hosten

Einführung

TensorFlow Serving ist ein flexibles, leistungsstarkes Modellierungssystem für maschinelles Lernen, das für Produktionsumgebungen entwickelt wurde. Mit TensorFlow Serving ist es einfach, mit TensorFlow erstellte Modelle zu hosten und APIs verfügbar zu machen.

Weitere Informationen finden Sie in der TensorFlow-Serving-Dokumentation (https://www.tensorflow.org/tfx/guide/serving).

Dieses Mal habe ich TensorFlow Serving auf AWS EC2 verwendet, um ein Deep-Learning-Modell von TensorFlow zu hosten. Am Ende des Artikels versuche ich auch Docker.

Verfahren

Erstellung einer EC2-Instanz

Geben Sie "Deep Learning AMI" in die AMI-Suchleiste ein, um nach dem AMI zu suchen, das Sie verwenden möchten. Dieses Mal habe ich "Deep Learning AMI (Ubuntu 18.04) Version 30.0 --ami-0b1b56cbf0f8fcea3" verwendet. Ich habe "p2.xlarge" als Instanztyp verwendet. Die Sicherheitsgruppe ist so eingestellt, dass ssh und http über die Entwicklungsumgebung verbunden werden können und alle anderen Einstellungen als Standardeinstellungen beibehalten werden.

Umgebung

Melden Sie sich bei EC2 an und erstellen Sie die Umgebung.

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

Das Installationsverfahren wird auf der offiziellen Website vorgestellt.

Fügen Sie zunächst den TensorFlow Serving URI zu sources.list.d hinzu.

~$ 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

Führen Sie die Installation durch.

~$ 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

Damit ist die Installation abgeschlossen.

Modellbau

Von hier aus erstellen wir ein Modell für die Bereitstellung. Bereiten Sie zunächst ein Arbeitsverzeichnis vor.

~$ mkdir tfexample
~$ cd tfexample

Starten Sie jupyter-lab und erstellen Sie das Modell.

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

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

Da es einen Ort gibt, an dem die URL in der Standardausgabe angezeigt wird, greifen Sie zu, indem Sie den Teil von 127.0.0.1 auf die IP-Adresse der Instanz umschreiben.

Wählen Sie nach dem Start von jupyer lab den Kernel conda_tensorflow2_py36 aus und öffnen Sie das Notizbuch. Benennen Sie es in "tfmodel.ipynb" um.

Dieses Mal werde ich ein Model mit Fashionmnist machen.

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

Das Speicherziel des Modells wurde vom Modul "tempfile" erstellt. Dieses Mal wird das Modell in / tmp / 1 gespeichert.

Modell Host

Öffnen Sie ein anderes Terminal, melden Sie sich bei der Instanz an und starten Sie den Server.

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

Es scheint, dass es eine Struktur geben sollte, die die Version unter "model_base_path" anzeigt und das Modell darunter gespeichert wird.

model_base_path/
 ├ 1/
 │ ├ assets/
 │ ├ variables/
 │ └ saved_model.pb
 ├ 2/
│ ├ (unten weggelassen)

Ich werde eine Anfrage stellen und sie überprüfen. Gehen Sie zurück zu Ihrem Notizbuch und stellen Sie eine Anfrage.

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

Senden Sie Daten im JSON-Format per POST. Die Daten werden für den Schlüssel "Instanzen" festgelegt, sie werden jedoch im Stapel vorhergesagt. Daher müssen Sie bei der Form vorsichtig sein.

Übrigens sind die Inhalte von "Vorhersagen" wie folgt.

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]

Die Wahrscheinlichkeiten für jede Klasse werden in der Liste gespeichert. Dies ist die gleiche Ausgabe wie der folgende Code.

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

Hosting mit 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

Die Einstiegspunkte sind wie folgt. Der RESTful-API-Port ist 8501, der gRPC-Port ist 8500 und der model_base_path ist $ {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}

Die Einstiegspunktdatei wird in / usr / bin / tf_serving_entrypoint.sh gespeichert und enthält tatsächlich den folgenden Code:

#!/bin/bash 

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

Wenn Sie Docker verwenden, müssen Sie daher lediglich den Modellspeicherpfad des Hosts in Dockers "model_base_path" einbinden.

Weitere Hinweise

Recommended Posts

Ich habe versucht, ein Deep-Learning-Modell von TensorFlow mit TensorFlow Serving zu hosten
Ich habe versucht, Pytorchs Deep-Learning-Modell mit TorchServe auf Amazon SageMaker zu hosten
Ich habe versucht, ein Beispielmodell von Pytorch mit TorchServe zu hosten
Ich habe versucht, mit Theano tief zu lernen
Ich habe versucht, in einem tief erlernten Sprachmodell zu schreiben
Ich habe versucht, ○ ✕ mit TensorFlow zu spielen
Ich habe versucht, tief zu lernen
Ich habe ein ○ ✕ Spiel mit TensorFlow gemacht
Ich habe mit dem TensorFlow --⑦ Lernmodell einen Dir en grey Gesichtsklassifikator erstellt
Ich habe versucht, Magenta / TensorFlow zu verwenden
Ich habe versucht, das CNN-Modell von TensorFlow mit TF-Slim umzugestalten
Ich habe versucht, Tensorboard zu verwenden, ein Visualisierungstool für maschinelles Lernen
Ich habe ein VGG16-Modell mit TensorFlow gemacht (unterwegs)
Ich habe versucht, mit PyBrain verstärkt zu lernen
Erstellen eines Lernmodells mit MNIST
Ich habe versucht, mit einer Schildkröte eine Linie zu ziehen
Bilderkennungsmodell mit Deep Learning im Jahr 2016
Aktienkursprognose mit Deep Learning (TensorFlow)
Ich habe versucht, Text mit TensorFlow zu klassifizieren
Ich habe versucht, pipenv zu verwenden, machen Sie sich also eine Notiz
[ML-Aents] Ich habe versucht, maschinelles Lernen mit Unity und TensorFlow of Python (v0.11β-kompatibel) zu lernen.
Ich habe mit TensorFlow --⑧ Learning Execution einen Dir en Grey Face Classifier erstellt
Ich habe die übliche Geschichte ausprobiert, Deep Learning zu verwenden, um den Nikkei-Durchschnitt vorherzusagen
Ich habe die gängige Geschichte der Vorhersage des Nikkei-Durchschnitts mithilfe von Deep Learning (Backtest) ausprobiert.
Eine Geschichte über einfaches maschinelles Lernen mit TensorFlow
Ein Amateur versuchte Deep Learning mit Caffe (Einführung)
Ein Amateur versuchte Deep Learning mit Caffe (Übung)
Aktienkursprognose mit Deep Learning (TensorFlow) -Teil 2-
Ich habe versucht, Pythonect, eine Programmiersprache für den Datenfluss, zu verwenden.
Ich habe versucht, eine CSV-Datei mit Python zu lesen
Ein Amateur hat Deep Learning mit Caffe ausprobiert (Übersicht)
Ich habe versucht, die Datenbank (sqlite3) mit kivy zu verwenden
Ich habe den Deep Learning Framework Chainer installiert
Erstellen Sie eine REST-API mit dem in Lobe und TensorFlow Serving erlernten Modell.
Ich habe versucht, die Strichzeichnung mit Deep Learning aus dem Bild zu extrahieren
Ich habe versucht, das Objekterkennungs-Tutorial mit dem neuesten Deep-Learning-Algorithmus auszuführen
Ich habe versucht, verschiedene Methoden für maschinelles Lernen (Vorhersagemodell) mithilfe von Scicit-Learn zu implementieren
Ich habe versucht, parametrisiert zu verwenden
Ich habe versucht, Argparse zu verwenden
Ich habe versucht, Mimesis zu verwenden
Ich habe versucht, anytree zu verwenden
Ich habe versucht, Summpy zu verwenden
Ich habe versucht, Coturn zu verwenden
Ich habe versucht, Pipenv zu verwenden
Ich habe versucht, Matplotlib zu verwenden
Ich habe versucht, "Anvil" zu verwenden.
Ich habe versucht, Hubot zu verwenden
Ich habe versucht, ESPCN zu verwenden
Ich habe versucht, openpyxl zu verwenden
Ich habe versucht, Ipython zu verwenden
Ich habe versucht, PyCaret zu verwenden
Ich habe versucht, Cron zu verwenden
Ich habe versucht, ngrok zu verwenden
Ich habe versucht, face_recognition zu verwenden
Ich habe versucht, Jupyter zu verwenden
Ich habe versucht, doctest zu verwenden