Giúp bảo vệ Great Barrier Reef với TensorFlow trên Kaggle Tham Challenge

Đào tạo và phục vụ mô hình TensorFlow với Phục vụ TensorFlow

Hướng dẫn này huấn luyện một mô hình mạng thần kinh để phân loại hình ảnh của quần áo, giống như đôi giày thể thao và áo sơ mi , tiết kiệm mô hình đào tạo, và sau đó phục vụ nó với TensorFlow Phục vụ . Trọng tâm là TensorFlow Phục vụ, chứ không phải là người mẫu và đào tạo trong TensorFlow, vì vậy cho một ví dụ hoàn chỉnh trong đó tập trung vào các mô hình đào tạo và xem các ví dụ Phân loại cơ bản .

Hướng dẫn này sử dụng tf.keras , một API cấp cao để xây dựng và đào tạo mô hình trong TensorFlow.

import sys

# Confirm that we're using Python 3
assert sys.version_info.major is 3, 'Oops, not running Python 3. Use Runtime > Change runtime type'
# TensorFlow and tf.keras
print("Installing dependencies for Colab environment")
!pip install -Uq grpcio==1.26.0

import tensorflow as tf
from tensorflow import keras

# Helper libraries
import numpy as np
import matplotlib.pyplot as plt
import os
import subprocess

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

Tạo mô hình của bạn

Nhập tập dữ liệu MNIST Thời trang

Hướng dẫn này sử dụng thời trang MNIST bộ dữ liệu, trong đó có 70.000 hình ảnh màu xám trong 10 hạng mục. Các hình ảnh hiển thị từng mặt hàng quần áo ở độ phân giải thấp (28 x 28 pixel), như được thấy ở đây:

Thời trang MNIST sprite
Hình 1. mẫu thời trang-MNIST (bởi Zalando, MIT License).

Thời trang MNIST được thiết kế như một thả thay thế cho các cổ điển MNIST dataset-thường được sử dụng như "Hello, World" của các chương trình học máy cho computer vision. Bạn có thể truy cập MNIST Thời trang trực tiếp từ TensorFlow, chỉ cần nhập và tải dữ liệu.

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))
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-labels-idx1-ubyte.gz
32768/29515 [=================================] - 0s 0us/step
40960/29515 [=========================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-images-idx3-ubyte.gz
26427392/26421880 [==============================] - 1s 0us/step
26435584/26421880 [==============================] - 1s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-labels-idx1-ubyte.gz
16384/5148 [===============================================================================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-images-idx3-ubyte.gz
4423680/4422102 [==============================] - 0s 0us/step
4431872/4422102 [==============================] - 0s 0us/step

train_images.shape: (60000, 28, 28, 1), of float64
test_images.shape: (10000, 28, 28, 1), of float64

Đào tạo và đánh giá mô hình của bạn

Hãy sử dụng CNN đơn giản nhất có thể, vì chúng tôi không tập trung vào phần mô hình hóa.

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, name='Dense')
])
model.summary()

testing = False
epochs = 5

model.compile(optimizer='adam', 
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=[keras.metrics.SparseCategoricalAccuracy()])
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         
_________________________________________________________________
Dense (Dense)                (None, 10)                13530     
=================================================================
Total params: 13,610
Trainable params: 13,610
Non-trainable params: 0
_________________________________________________________________
Epoch 1/5
1875/1875 [==============================] - 10s 2ms/step - loss: 0.5376 - sparse_categorical_accuracy: 0.8135
Epoch 2/5
1875/1875 [==============================] - 3s 2ms/step - loss: 0.3919 - sparse_categorical_accuracy: 0.8637
Epoch 3/5
1875/1875 [==============================] - 3s 2ms/step - loss: 0.3568 - sparse_categorical_accuracy: 0.8740
Epoch 4/5
1875/1875 [==============================] - 3s 2ms/step - loss: 0.3378 - sparse_categorical_accuracy: 0.8801
Epoch 5/5
1875/1875 [==============================] - 3s 2ms/step - loss: 0.3231 - sparse_categorical_accuracy: 0.8846
313/313 [==============================] - 1s 1ms/step - loss: 0.3589 - sparse_categorical_accuracy: 0.8739

Test accuracy: 0.8738999962806702

Lưu mô hình của bạn

Để tải mô hình đào tạo của chúng tôi vào TensorFlow Phục vụ chúng tôi đầu tiên cần phải lưu nó trong SavedModel định dạng. Thao tác này sẽ tạo tệp protobuf trong hệ thống phân cấp thư mục được xác định rõ và sẽ bao gồm số phiên bản. TensorFlow Phục vụ cho phép chúng ta chọn phiên bản của một mô hình, hay "thể phân phát" chúng tôi muốn sử dụng khi chúng ta đưa ra yêu cầu suy luận. Mỗi phiên bản sẽ được xuất sang một thư mục con khác nhau theo đường dẫn đã cho.

# Fetch the Keras session and save the model
# The signature definition is defined by the input and output tensors,
# and stored with the default serving key
import tempfile

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:absl:Function `_wrapped_model` contains input name(s) Conv1_input with unsupported characters which will be renamed to conv1_input in the SavedModel.
2021-11-09 11:02:24.983534: W tensorflow/python/util/util.cc:348] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
INFO:tensorflow:Assets written to: /tmp/1/assets
INFO:tensorflow:Assets written to: /tmp/1/assets
Saved model:
total 96
drwxr-xr-x 2 kbuilder kbuilder  4096 Nov  9 11:02 assets
-rw-rw-r-- 1 kbuilder kbuilder  8204 Nov  9 11:02 keras_metadata.pb
-rw-rw-r-- 1 kbuilder kbuilder 74677 Nov  9 11:02 saved_model.pb
drwxr-xr-x 2 kbuilder kbuilder  4096 Nov  9 11:02 variables

Kiểm tra mô hình đã lưu của bạn

Chúng tôi sẽ sử dụng lệnh tiện ích dòng saved_model_cli nhìn vào MetaGraphDefs (các mô hình) và SignatureDefs (những phương pháp bạn có thể gọi) trong SavedModel của chúng tôi. Xem thảo luận này của SavedModel CLI trong Hướng dẫn TensorFlow.

saved_model_cli show --dir {export_path} --all
MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:

signature_def['__saved_model_init_op']:
  The given SavedModel SignatureDef contains the following input(s):
  The given SavedModel SignatureDef contains the following output(s):
    outputs['__saved_model_init_op'] tensor_info:
        dtype: DT_INVALID
        shape: unknown_rank
        name: NoOp
  Method name is: 

signature_def['serving_default']:
  The given SavedModel SignatureDef contains the following input(s):
    inputs['Conv1_input'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 28, 28, 1)
        name: serving_default_Conv1_input:0
  The given SavedModel SignatureDef contains the following output(s):
    outputs['Dense'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 10)
        name: StatefulPartitionedCall:0
  Method name is: tensorflow/serving/predict
Traceback (most recent call last):
  File "/tmpfs/src/tf_docs_env/bin/saved_model_cli", line 8, in <module>
    sys.exit(main())
  File "/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/tools/saved_model_cli.py", line 1204, in main
    args.func(args)
  File "/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/tools/saved_model_cli.py", line 729, in show
    _show_all(args.dir)
  File "/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/tools/saved_model_cli.py", line 308, in _show_all
    _show_defined_functions(saved_model_dir)
  File "/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/tools/saved_model_cli.py", line 188, in _show_defined_functions
    trackable_object = load.load(saved_model_dir)
  File "/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/saved_model/load.py", line 864, in load
    result = load_internal(export_dir, tags, options)["root"]
  File "/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/saved_model/load.py", line 903, in load_internal
    ckpt_options, options, filters)
  File "/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/saved_model/load.py", line 162, in __init__
    self._load_all()
  File "/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/saved_model/load.py", line 259, in _load_all
    self._load_nodes()
  File "/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/saved_model/load.py", line 448, in _load_nodes
    slot_variable = optimizer_object.add_slot(
AttributeError: '_UserObject' object has no attribute 'add_slot'

Điều đó cho chúng tôi biết rất nhiều về mô hình của chúng tôi! Trong trường hợp này, chúng tôi chỉ đào tạo mô hình của mình, vì vậy chúng tôi đã biết các đầu vào và đầu ra, nhưng nếu chúng tôi không thực hiện thì đây sẽ là thông tin quan trọng. Nó không cho chúng ta biết tất cả mọi thứ, chẳng hạn như đây là dữ liệu hình ảnh thang độ xám, nhưng đó là một khởi đầu tuyệt vời.

Phục vụ mô hình của bạn với TensorFlow Serving

Thêm URI phân phối phục vụ TensorFlow làm nguồn gói:

Chúng tôi đang chuẩn bị để cài đặt TensorFlow Phục vụ sử dụng Aptitude từ Colab này chạy trong một môi trường Debian. Chúng tôi sẽ thêm tensorflow-model-server gói vào danh sách các gói mà Aptitude biết về. Lưu ý rằng chúng tôi đang chạy dưới dạng root.

import sys
# We need sudo prefix if not on a Google Colab.
if 'google.colab' not in sys.modules:
  SUDO_IF_NEEDED = 'sudo'
else:
  SUDO_IF_NEEDED = ''
# This is the same as you would do from your command line, but without the [arch=amd64], and no sudo
# You would instead do:
# 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 -

!echo "deb http://storage.googleapis.com/tensorflow-serving-apt stable tensorflow-model-server tensorflow-model-server-universal" | {SUDO_IF_NEEDED} tee /etc/apt/sources.list.d/tensorflow-serving.list && \
curl https://storage.googleapis.com/tensorflow-serving-apt/tensorflow-serving.release.pub.gpg | {SUDO_IF_NEEDED} apt-key add -
!{SUDO_IF_NEEDED} apt update
deb 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   4340      0 --:--:-- --:--:-- --:--:--  4340
OK
Hit:1 http://asia-east1.gce.archive.ubuntu.com/ubuntu bionic InRelease
Get:2 http://asia-east1.gce.archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB]
Get:3 http://asia-east1.gce.archive.ubuntu.com/ubuntu bionic-backports InRelease [74.6 kB]
Hit:4 https://nvidia.github.io/libnvidia-container/stable/ubuntu18.04/amd64  InRelease
Get:5 https://nvidia.github.io/nvidia-container-runtime/ubuntu18.04/amd64  InRelease [1481 B]
Hit:6 https://nvidia.github.io/nvidia-docker/ubuntu18.04/amd64  InRelease
Get:7 http://storage.googleapis.com/tensorflow-serving-apt stable InRelease [3012 B]
Ign:8 http://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64  InRelease
Hit:9 http://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64  Release
Get:10 https://packages.cloud.google.com/apt eip-cloud-bionic InRelease [5419 B]
Get:11 http://packages.cloud.google.com/apt google-cloud-logging-wheezy InRelease [5483 B]
Get:12 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB]
Hit:14 http://archive.canonical.com/ubuntu bionic InRelease
Err:10 https://packages.cloud.google.com/apt eip-cloud-bionic InRelease
  The following signatures couldn't be verified because the public key is not available: NO_PUBKEY FEEA9169307EA071 NO_PUBKEY 8B57C5C2836F4BEB
Get:15 http://storage.googleapis.com/tensorflow-serving-apt stable/tensorflow-model-server amd64 Packages [339 B]
Err:11 http://packages.cloud.google.com/apt google-cloud-logging-wheezy InRelease
  The following signatures couldn't be verified because the public key is not available: NO_PUBKEY FEEA9169307EA071 NO_PUBKEY 8B57C5C2836F4BEB
Get:16 http://storage.googleapis.com/tensorflow-serving-apt stable/tensorflow-model-server-universal amd64 Packages [348 B]
Fetched 268 kB in 1s (240 kB/s)



113 packages can be upgraded. Run 'apt list --upgradable' to see them.
W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: https://packages.cloud.google.com/apt eip-cloud-bionic InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY FEEA9169307EA071 NO_PUBKEY 8B57C5C2836F4BEB
W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: http://packages.cloud.google.com/apt google-cloud-logging-wheezy InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY FEEA9169307EA071 NO_PUBKEY 8B57C5C2836F4BEB
W: Failed to fetch https://packages.cloud.google.com/apt/dists/eip-cloud-bionic/InRelease  The following signatures couldn't be verified because the public key is not available: NO_PUBKEY FEEA9169307EA071 NO_PUBKEY 8B57C5C2836F4BEB
W: Failed to fetch http://packages.cloud.google.com/apt/dists/google-cloud-logging-wheezy/InRelease  The following signatures couldn't be verified because the public key is not available: NO_PUBKEY FEEA9169307EA071 NO_PUBKEY 8B57C5C2836F4BEB
W: Some index files failed to download. They have been ignored, or old ones used instead.

Cài đặt phục vụ TensorFlow

Đây là tất cả những gì bạn cần - một dòng lệnh!

{SUDO_IF_NEEDED} apt-get install tensorflow-model-server
The following packages were automatically installed and are no longer required:
  linux-gcp-5.4-headers-5.4.0-1040 linux-gcp-5.4-headers-5.4.0-1043
  linux-gcp-5.4-headers-5.4.0-1044 linux-gcp-5.4-headers-5.4.0-1049
  linux-headers-5.4.0-1049-gcp linux-image-5.4.0-1049-gcp
  linux-modules-5.4.0-1044-gcp linux-modules-5.4.0-1049-gcp
  linux-modules-extra-5.4.0-1049-gcp
Use 'sudo apt autoremove' to remove them.
The following NEW packages will be installed:
  tensorflow-model-server
0 upgraded, 1 newly installed, 0 to remove and 113 not upgraded.
Need to get 335 MB of archives.
After this operation, 0 B of additional disk space will be used.
Get:1 http://storage.googleapis.com/tensorflow-serving-apt stable/tensorflow-model-server amd64 tensorflow-model-server all 2.7.0 [335 MB]
Fetched 335 MB in 7s (49.2 MB/s)
Selecting previously unselected package tensorflow-model-server.
(Reading database ... 283435 files and directories currently installed.)
Preparing to unpack .../tensorflow-model-server_2.7.0_all.deb ...
Unpacking tensorflow-model-server (2.7.0) ...
Setting up tensorflow-model-server (2.7.0) ...

Bắt đầu chạy TensorFlow Serving

Đây là nơi chúng tôi bắt đầu chạy TensorFlow Serving và tải mô hình của chúng tôi. Sau khi nó tải, chúng ta có thể bắt đầu thực hiện các yêu cầu suy luận bằng cách sử dụng REST. Có một số thông số quan trọng:

  • rest_api_port : Các cổng mà bạn sẽ sử dụng cho các yêu cầu REST.
  • model_name : Bạn sẽ sử dụng trong URL của yêu cầu REST. Nó có thể là bất cứ thứ gì.
  • model_base_path : Đây là đường dẫn đến thư mục mà bạn đã lưu mô hình của bạn.
os.environ["MODEL_DIR"] = MODEL_DIR
nohup tensorflow_model_server \
  --rest_api_port=8501 \
  --model_name=fashion_model \
  --model_base_path="${MODEL_DIR}" >server.log 2>&1
tail server.log

Đưa ra yêu cầu đối với mô hình của bạn trong TensorFlow Serving

Đầu tiên, hãy xem một ví dụ ngẫu nhiên từ dữ liệu thử nghiệm của chúng tôi.

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

import random
rando = random.randint(0,len(test_images)-1)
show(rando, 'An Example Image: {}'.format(class_names[test_labels[rando]]))

png

Ok, điều đó có vẻ thú vị. Bạn khó nhận ra điều đó như thế nào? Bây giờ, hãy tạo đối tượng JSON cho một loạt ba yêu cầu suy luận và xem mô hình của chúng tôi nhận dạng mọi thứ tốt như thế nào:

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]]]]}

Thực hiện các yêu cầu REST

Phiên bản mới nhất của dịch vụ

Chúng tôi sẽ gửi một yêu cầu dự đoán dưới dạng POST tới điểm cuối REST của máy chủ và chuyển cho nó ba ví dụ. Chúng tôi sẽ yêu cầu máy chủ của chúng tôi cung cấp cho chúng tôi phiên bản mới nhất của dịch vụ của chúng tôi bằng cách không chỉ định một phiên bản cụ thể.

!pip install -q requests

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]))

Một phiên bản cụ thể của dịch vụ

Bây giờ hãy chỉ định một phiên bản cụ thể của dịch vụ của chúng tôi. Vì chúng tôi chỉ có một, hãy chọn phiên bản 1. Chúng tôi cũng sẽ xem xét cả ba kết quả.

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

for i in range(0,3):
  show(i, 'The model thought this was a {} (class {}), and it was actually a {} (class {})'.format(
    class_names[np.argmax(predictions[i])], np.argmax(predictions[i]), class_names[test_labels[i]], test_labels[i]))