Skip to content

Instantly share code, notes, and snippets.

@hoangnt2601
Last active April 4, 2020 10:36
Show Gist options
  • Select an option

  • Save hoangnt2601/794654e9e07c13d9ce47fea3641802bc to your computer and use it in GitHub Desktop.

Select an option

Save hoangnt2601/794654e9e07c13d9ce47fea3641802bc to your computer and use it in GitHub Desktop.
Triển khai mô hình học sâu sử dụng Tensorflow 2.0 với Cloud Functions

Triển khai mô hình học sâu sử dụng Tensorflow 2.0 với Cloud Functions

TensorFlow là một framework để triển khai mô hình học sâu. Các bản cập nhật gần đây cho phiên bản 2.0 cung cấp một số cải tiến, bao gồm những thay đổi quan trọng đối với eager execution. Google Cloud Function cung cấp cách thức thuận tiện, có thể mở rộng trong cơ sở hạ tầng Google Cloud.

Nội dung notebook bao gồm:

  • Cách cài đặt và triển khai Google Cloud Function
  • Cách lưu trữ mô hình
  • Làm thế nào để sử dụng Cloud Functions API endpoint

Các thành phần của hệ thống

Google Cloud Platform (GCP) cung cấp nhiều cách để triển khai trong điện toán đám mây. Hãy để so sánh các phương pháp sau đây để triển khai mô hình:

TensorFlow Serving

Thông thường, bạn có thể sử dụng một cụm (cluster) làm inference cho mô hình. Trong trường hợp này, TF serving sẽ là một cách tuyệt vời để tổ chức inference trên một hoặc nhiều máy ảo (VMs), tất cả những gì bạn cần làm là thêm một bộ cân bằng tải (load balancer) trên đầu cụm. Bạn có thể sử dụng các sản phẩm sau để triển khai phân phát TF trong Nền tảng AI:

Cách tiếp cận này có những ưu điểm sau:

  • Thời gian đáp ứng tuyệt vời vì mô hình sẽ được tải trong bộ nhớ
  • Chi phí cho mỗi lần chạy sẽ giảm đáng kể khi bạn có nhiều request

TensorFlow Serving.png

AI Platform Predictions

Nền tảng AI cung cấp một cách dễ dàng để triển khai các mô hình đã được huấn luyện (pre-trained) thông qua AI Platform Predictions. Điều này có nhiều lợi thế inference khi so sánh với phương pháp cụm:

  • Cơ sở hạ tầng dễ mở rộng
  • Không cần quản lý cơ sở hạ tầng
  • Lưu trữ riêng cho mô hình, rất thuận tiện để theo dõi các phiên bản của mô hình và để so sánh hiệu năng của chúng

Cloud Functions

Khi so sánh Deep Learning VM imagesAI Platform Predictions, phương pháp serverless cung cấp các ưu điểm sau:

  • Code dễ cài đặt và triển khai
  • Khả năng mở rộng tuyệt vời, cho phép bạn mở rộng từ 0 đến 10k gần như ngay lập tức
  • Cấu trúc chi phí cho phép bạn chỉ trả tiền cho các lần chạy, nghĩa là bạn không phải trả tiền cho các máy chủ nhàn rỗi.
  • Khả năng sử dụng các phiên bản tùy chỉnh của các framework như Tensorflow 2.0 hay PyTorch

So sánh trong bảng sau:

Cloud Functions table.png

Nhược điểm sẽ là trong trường hợp mô hình quá lớn, khởi động có thể mất một thời gian và sẽ rất khó để đạt được hiệu năng thời gian thực. Ngoài ra, chúng ta cần lưu ý rằng cơ sở hạ tầng không có máy chủ (serverless) là giá của một cá nhân sử dụng sẽ giảm khi bạn không có một số lượng lớn request. Vì vậy, trong trường hợp này, có thể rẻ hơn khi sử dụng TF serving.

TF serving as inference.png

Mặt khác, Cloud Functions có thanh toán trên 100ms mà không có khoảng thời gian tối thiểu. Điều này có nghĩa là Cloud Functions rất tốt cho các công việc ngắn, không nhất quán nhưng nếu bạn cần xử lý một chuỗi công việc dài, nhất quán, Compute Engine có thể là lựa chọn tốt hơn.

Tổng quan kiến trúc

Hệ thống của chúng ta sẽ khá đơn giản. Chúng ta sẽ huấn luyện mô hình ở máy tính cá nhân và sau đó tải nó lên Google Cloud. Cloud Functions sẽ được gọi thông qua API và sẽ tải xuống mô hình và ảnh test từ Cloud Storage.

cloud function Architecture Overview.png

Có một số điều cần xem xét khi bạn thiết kế một hệ thống serverless:

Thứ nhất, ghi nhớ sự khác biệt giữa cold invocation. Khi chức năng cần thời gian để tải xuống và khởi tạo một mô hình và để warm invocation, khi chức năng sử dụng cached model. Việc tăng warm invocation không giúp tăng tốc độ sử lí. Cách khắc phục có thể sử dụng cơ chế pub/sub để normalize việc load do đó nó sẽ được sử lí bởi warm containers.

Thứ hai, bạn có thể sử dụng batching để tối ưu chi phí và tăng tốc độ sử lí. Bởi một mô hình có thể chạy dưới dạng batch thay vì chạy trong mỗi image. Batching cho phép bạn giảm sự khác biệt giữa cold và warm cải thiện tốc độ tổng thể.

Cuối cùng, bạn có thể lưu một phần mô hình của mình như một phần của thư viện. Bạn cũng có thể thử chia mô hình thành các lớp và xâu chuỗi chúng lại với nhau trên các chức năng riêng biệt. Trong trường hợp này, mỗi chức năng sẽ gửi một tầng kích hoạt (activity layer) trung gian xuống chuỗi và không có chức năng nào cần phải tải xuống mô hình.

TensorFlow 2.0 example

Ta sử dụng bài toán MNIST fashion với TensorFlow 2.0 làm ví dụ:

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

import tensorflow as tf

from tensorflow.keras.layers import Dense, Flatten, Conv2D
from tensorflow.keras import Model
EPOCHS = 10

mnist = tf.keras.datasets.mnist
fashion_mnist = tf.keras.datasets.fashion_mnist

(x_train, y_train), (x_test, y_test) = fashion_mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

# Add a channels dimension e.g. (60000, 28, 28) => (60000, 28, 28, 1)
x_train = x_train[..., tf.newaxis]
x_test = x_test[..., tf.newaxis]

train_ds = tf.data.Dataset.from_tensor_slices(
    (x_train, y_train)).shuffle(10000).batch(32)
test_ds = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(32)

class CustomModel(Model):
  def __init__(self):
    super(CustomModel, self).__init__()
    self.conv1 = Conv2D(32, 3, activation='relu')
    self.flatten = Flatten()
    self.d1 = Dense(128, activation='relu')
    self.d2 = Dense(10, activation='softmax')
    
  def call(self, x):
    x = self.conv1(x)
    x = self.flatten(x)
    x = self.d1(x)
    return self.d2(x)

model = CustomModel()

loss_object = tf.keras.losses.SparseCategoricalCrossentropy()
optimizer = tf.keras.optimizers.Adam()

train_loss = tf.keras.metrics.Mean(name='train_loss')
train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='train_accuracy')

test_loss = tf.keras.metrics.Mean(name='test_loss')
test_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='test_accuracy')

@tf.function
def train_step(images, labels):
  with tf.GradientTape() as tape:
    predictions = model(images)
    loss = loss_object(labels, predictions)
  gradients = tape.gradient(loss, model.trainable_variables)
  optimizer.apply_gradients(zip(gradients, model.trainable_variables))

  train_loss(loss)
  train_accuracy(labels, predictions)

@tf.function
def test_step(images, labels):
  predictions = model(images)
  t_loss = loss_object(labels, predictions)

  test_loss(t_loss)
  test_accuracy(labels, predictions)

for epoch in range(EPOCHS):
  for images, labels in train_ds:
    train_step(images, labels)

  for test_images, test_labels in test_ds:
    test_step(test_images, test_labels)

  template = 'Epoch {}, Loss: {}, Accuracy: {}, Test Loss: {}, Test Accuracy: {}'
  print (template.format(epoch+1,
                         train_loss.result(),
                         train_accuracy.result()*100,
                         test_loss.result(),
                         test_accuracy.result()*100))

# Save the weights
model.save_weights('fashion_mnist_weights')

Sau quá trình huấn luyện tạo ra các tệp sau:

fashion_mnist_weights_new.index
fashion_mnist_weights.data-00000-of-00001

Chúng ta sẽ cần lưu trữ mô hình riêng biệt với code vì có giới hạn về kích thước tệp cục bộ trên Cloud Functions. Bạn có thể tải chúng lên Cloud Storage cùng với test image.

Cloud Functions

Một trong những ưu điểm chính của Cloud Function là bạn không phải tạo gói thư viện thủ công. Bạn chỉ có thể sử dụng tệp requirements.txt như trong python và liệt kê tất cả các thư viện được sử dụng như dưới đây. Ngoài ra, hãy nhớ để mô hình là một biến toàn cục để nó sẽ được lưu trữ và sử dụng lại trong warm invocations của Cloud Functions.

# requirements.txt
tensorflow==2.0
google-cloud-storage==1.16.1
Pillow==6.0.0

Triển khai mô hình với Cloud Functions:

import numpy
import tensorflow

from google.cloud import storage
from tensorflow.keras.layers import Dense, Flatten, Conv2D
from tensorflow.keras import Model
from PIL import Image


# We keep model as global variable so we don't have to reload it in case of warm invocations
model = None

class CustomModel(Model):
  def __init__(self):
    super(CustomModel, self).__init__()
    self.conv1 = Conv2D(32, 3, activation='relu')
    self.flatten = Flatten()
    self.d1 = Dense(128, activation='relu')
    self.d2 = Dense(10, activation='softmax')

  def call(self, x):
    x = self.conv1(x)
    x = self.flatten(x)
    x = self.d1(x)
    return self.d2(x)

def download_blob(bucket_name, source_blob_name, destination_file_name):
    """Downloads a blob from the bucket."""
    storage_client = storage.Client()
    bucket = storage_client.get_bucket(bucket_name)
    blob = bucket.blob(source_blob_name)

    blob.download_to_filename(destination_file_name)

    print('Blob {} downloaded to {}.'.format(
        source_blob_name,
        destination_file_name))

def handler(request):
    global model
    class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']

    # Model load which only happens during cold starts
    if model is None:
        download_blob('<your_bucket_name>', 'tensorflow/fashion_mnist_weights.index', '/tmp/fashion_mnist_weights.index')
        download_blob('<your_bucket_name>', 'tensorflow/fashion_mnist_weights.data-00000-of-00001', '/tmp/fashion_mnist_weights.data-00000-of-00001')
        model = CustomModel()
        model.load_weights('/tmp/fashion_mnist_weights')
    
    download_blob('<your_bucket_name>', 'tensorflow/test.png', '/tmp/test.png')
    image = numpy.array(Image.open('/tmp/test.png'))
    input_np = (numpy.array(Image.open('/tmp/test.png'))/255)[numpy.newaxis,:,:,numpy.newaxis]
    predictions = model.call(input_np)
    print(predictions)
    print("Image is "+class_names[numpy.argmax(predictions)])
    
    return class_names[numpy.argmax(predictions)]

Deployment bằng command line

Bạn có thể dễ dàng triển khai và chạy Cloud Function bằng gcloud.

git clone https://github.com/ryfeus/gcf-packs
cd gcf-packs/tensorflow2.0/example/
gcloud functions deploy handler --runtime python37 --trigger-http --memory 2048
gcloud functions call handler

response:

executionId: omx2o2y27sm9
result: Trouser

Deployment bằng web console

Đầu tiên, hãy để bắt đầu từ bảng điều khiển Cloud Function. Để tạo một Cloud Function mới, hãy chọn nút "Create function". Trong cửa sổ "Create function", hãy đặt tên chức năng là tensorflow2demo, bộ nhớ được phân bổ (2 GB trong trường hợp của chúng tôi để có hiệu năng tốt nhất), trigger là HTTP và runtime trên python 3.7

cloud functions create function.png

Tiếp theo, các tệp main.py và requirements.txt. Bạn chỉ có thể sao chép mã tại repo. Cuối cùng, hãy nhấn nút "Create" và khởi tạo chức năng.

main py.png

Sau khi chức năng được triển khai, bạn có thể kiểm tra nó trong phần Testing trên dashboard. Bạn cũng có thể tùy chỉnh các sự kiện đến và xem đầu ra cũng như logs.

tensorflow demo.png

tensorflow logs.png

Như bạn có thể thấy, mô hình đã phân loại thành công hình ảnh là quần. Nếu chúng ta chạy các chức năng một lần nữa, chúng ta sẽ thấy rằng nó sẽ chạy nhanh hơn rất nhiều bởi vì chúng ta đã lưu mô hình vào bộ đệm.

tensorflow logs 2.png

Tham khảo

https://cloud.google.com/blog/products/ai-machine-learning/how-to-serve-deep-learning-models-using-tensorflow-2-0-with-cloud-functions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment