透過 Vertex AI 中的預先訓練 TensorFlow 圖片模型取得預測結果

1. 總覽

在本實驗室中,您將使用 Vertex AI,從預先訓練的圖像分類模型取得預測結果。

課程內容

學習重點:

  • 將 TensorFlow 模型匯入 Vertex AI Model Registry
  • 取得線上預測
  • 更新 TensorFlow Serving 函式

在 Google Cloud 中執行這個研究室的總費用約為 $1 美元。

2. Vertex AI 簡介

這個實驗室使用 Google Cloud 最新推出的 AI 產品服務。Vertex AI 整合了 Google Cloud 中的機器學習產品,提供流暢的開發體驗。先前,使用 AutoML 訓練的模型和自訂模型必須透過不同的服務存取。新產品將這兩項功能與其他新產品整合至單一 API。您也可以將現有專案遷移至 Vertex AI。

Vertex AI 包含許多不同產品,可支援端對端機器學習工作流程。本研究室將著重於以下產品:PredictionsWorkbench

Vertex 產品總覽

3. 應用情境總覽

在本實驗室中,您將瞭解如何從 TensorFlow Hub 取得預先訓練模型,並部署至 Vertex AI。TensorFlow Hub 是各種問題領域的訓練模型存放區,例如嵌入、文字產生、語音轉文字、圖像分割等。

本實驗室使用的範例是MobileNet V1 圖片分類模型,已預先訓練 ImageNet 資料集。只要利用 TensorFlow Hub 或其他類似深度學習存放區提供的現成模型,您就能為多項預測工作部署高品質的機器學習模型,而不必擔心模型訓練的問題。

4. 設定環境

您必須擁有啟用計費功能的 Google Cloud Platform 專案,才能執行這個程式碼研究室。如要建立專案,請按照這篇文章中的操作說明進行。

步驟 1:啟用 Compute Engine API

前往「Compute Engine」,然後選取「啟用」 (如果尚未啟用)。

步驟 2:啟用 Vertex AI API

前往 Cloud 控制台的 Vertex AI 專區,然後點選「啟用 Vertex AI API」

Vertex AI 資訊主頁

步驟 3:建立 Vertex AI Workbench 執行個體

在 Cloud 控制台的 Vertex AI 專區中,按一下 Workbench:

Vertex AI 選單

如果尚未啟用 Notebooks API,請先啟用。

Notebook_api

啟用後,按一下「MANAGED NOTEBOOKS」

Notebooks_UI

然後選取「新增筆記本」

new_notebook

為筆記本命名,然後在「權限」下方選取「服務帳戶」

create_notebook

選取「進階設定」

在「安全性」下方,選取「啟用終端機」(如果尚未啟用)。

enable_terminal

您可以保留其他進階設定。

接著,按一下「建立」。執行個體的佈建作業會在幾分鐘內完成。

建立執行個體後,請選取「OPEN JUPYTERLAB」

open_jupyterlab

5. 註冊模型

步驟 1:將模型上傳至 Cloud Storage

點選這個連結前往 TensorFlow Hub 頁面,取得以 ImagNet 資料集訓練的 MobileNet V1 模型。

選取「下載」即可下載已儲存的模型構件。

download_model

在 Google Cloud 控制台的 Cloud Storage 專區中,選取「建立」

create_bucket

為值區命名,並選取 us-central1 做為區域。接著點選「建立」

specify_bucket

將下載的 TensorFlow 中心模型上傳至值區。請務必先解壓縮檔案。

gcs_model

你的分桶應如下所示:

imagenet_mobilenet_v1_050_128_classification_5/
  saved_model.pb
  variables/
    variables.data-00000-of-00001
    variables.index

步驟 2:將模型匯入註冊資料庫

前往 Cloud 控制台的 Vertex AI「Model Registry」專區。

model_registry

選取「匯入」

選取「Import as new model」(匯入為新模型),然後為模型命名。

name_and_region

在「模型設定」下方,指定最新的預先建構 TensorFlow 容器。接著,選取您儲存模型構件的 Cloud Storage 路徑。

select_container

您可以略過「可解釋性」部分。

然後選取「匯入」

匯入完成後,您會在模型註冊中心看到模型

imported_model

6. 部署模型

在模型登錄檔中,選取模型右側的三點圖示,然後按一下「部署至端點」

deploy_model

在「定義端點」下方,選取「建立新端點」,然後為端點命名。

在「Model settings」(模型設定) 下方,將「Maximum number of compute nodes」(計算節點的最大數量) 設為 1,並將機器類型設為 n1-standard-2,其他設定則維持不變。然後按一下「DEPLOY」

endpoint_settings

部署完成後,部署作業狀態會變更為「Deployed on Vertex AI」

deploy_status

7. 取得預測結果

開啟您在設定步驟中建立的 Workbench 筆記本。在啟動器中建立新的 TensorFlow 2 筆記本。

tf_nb

執行以下儲存格,匯入必要的程式庫

from google.cloud import aiplatform

import tensorflow as tf
import numpy as np
from PIL import Image

您從 TensorFlow Hub 下載的 MobileNet 模型是使用 ImageNet 資料集訓練而成。MobileNet 模型的輸出結果是與 ImageNet 資料集類別標籤相對應的數字。如要將該數字翻譯成字串標籤,請下載圖片標籤。

# Download image labels

labels_path = tf.keras.utils.get_file('ImageNetLabels.txt','https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt')
imagenet_labels = np.array(open(labels_path).read().splitlines())

為了到達端點,您必須定義端點資源。請務必替換 {PROJECT_NUMBER}{ENDPOINT_ID}

PROJECT_NUMBER = "{PROJECT_NUMBER}"
ENDPOINT_ID = "{ENDPOINT_ID}"

endpoint = aiplatform.Endpoint(
    endpoint_name=f"projects/{PROJECT_NUMBER}/locations/us-central1/endpoints/{ENDPOINT_ID}")

您可以在控制台首頁找到專案編號。

project_number

以及 Vertex AI「Endpoints」部分的端點 ID。

endpoint_id

接下來,您將測試端點。

首先,請下載下列圖片並上傳至執行個體。

test_image

使用 PIL 開啟圖片。然後將大小和縮放比例調整為 255。請注意,您可以在模型的 TensorFlow 中心頁面找到模型預期的圖片大小。

IMAGE_PATH = "test-image.jpg"
IMAGE_SIZE = (128, 128)

im = Image.open(IMAGE_PATH)
im = im.resize(IMAGE_SIZE
im = np.array(im)/255.0

接下來,請將 NumPy 資料轉換為清單,以便在 HTTP 要求的主體中傳送。

x_test = im.astype(np.float32).tolist()

最後,請向端點發出預測呼叫,然後查詢對應的字串標籤。

# make prediction request
result = endpoint.predict(instances=[x_test]).predictions

# post process result
predicted_class = tf.math.argmax(result[0], axis=-1)
string_label = imagenet_labels[predicted_class]

print(f"label ID: {predicted_class}")
print(f"string label: {string_label}")

8. [選用] 使用 TF Serving 最佳化預測結果

如要取得更實際的範例,您可能會想要直接將圖片傳送至端點,而不是先在 NumPy 中載入圖片。這麼做效率較高,但您必須修改 TensorFlow 模型的服務函式。您必須進行修改,才能將輸入資料轉換為模型預期的格式。

步驟 1:修改放送函式

開啟新的 TensorFlow 筆記本,並匯入必要的程式庫。

from google.cloud import aiplatform

import tensorflow as tf

這次您要使用 hub.KerasLayer 將模型載入 TensorFlow,並將 TensorFlow AES 納入為 Keras 層,而非下載已儲存的模型構件。如要建立模型,您可以使用 Keras Sequential API,並將下載的 TF Hub 模型做為圖層,然後指定模型的輸入形狀。

tfhub_model = tf.keras.Sequential(
    [hub.KerasLayer("https://tfhub.dev/google/imagenet/mobilenet_v1_050_128/classification/5")]
)
tfhub_model.build([None, 128, 128, 3])

將 URI 定義為您稍早建立的值區。

BUCKET_URI = "gs://{YOUR_BUCKET}"
MODEL_DIR = BUCKET_URI + "/bytes_model"

您將要求傳送至線上預測伺服器時,HTTP 伺服器會接收該項要求。HTTP 伺服器會從 HTTP 要求內容主體擷取預測要求。擷取的預測要求會轉送至提供函式。對於 Vertex AI 預建的預測容器,要求內容會以 tf.string 的形式傳遞至服務函式。

如要將圖片傳送至預測服務,您必須將壓縮的圖片位元組編碼為 Base64,這樣才能確保內容不會在透過網路傳輸二進位資料時遭到修改。

由於已部署的模型預期輸入資料為原始 (未壓縮) 位元組,因此您必須確保 base 64 編碼資料會轉換回原始位元組 (例如 JPEG),然後再將其預先處理以符合模型輸入要求,再將其做為輸入內容傳遞至已部署的模型。

如要解決這個問題,您可以定義服務函式 (serving_fn),並將其附加至模型做為預處理步驟。您可以新增 @tf.function 修飾符,讓服務函式與基礎模型融合 (而非 CPU 上的上游)。

CONCRETE_INPUT = "numpy_inputs"


def _preprocess(bytes_input):
    decoded = tf.io.decode_jpeg(bytes_input, channels=3)
    decoded = tf.image.convert_image_dtype(decoded, tf.float32)
    resized = tf.image.resize(decoded, size=(128, 128))
    return resized


@tf.function(input_signature=[tf.TensorSpec([None], tf.string)])
def preprocess_fn(bytes_inputs):
    decoded_images = tf.map_fn(
        _preprocess, bytes_inputs, dtype=tf.float32, back_prop=False
    )
    return {
        CONCRETE_INPUT: decoded_images
    }  # User needs to make sure the key matches model's input


@tf.function(input_signature=[tf.TensorSpec([None], tf.string)])
def serving_fn(bytes_inputs):
    images = preprocess_fn(bytes_inputs)
    prob = m_call(**images)
    return prob


m_call = tf.function(tfhub_model.call).get_concrete_function(
    [tf.TensorSpec(shape=[None, 128, 128, 3], dtype=tf.float32, name=CONCRETE_INPUT)]
)

tf.saved_model.save(tfhub_model, MODEL_DIR, signatures={"serving_default": serving_fn})

當您以 HTTP 要求封包傳送預測資料時,圖片資料會以 base64 編碼,但 TensorFlow 模型會採用 numpy 輸入。您的服務函式會將 base64 轉換為 numpy 陣列。

提出預測要求時,您需要將要求導向服務函式,而不是模型,因此您必須知道服務函式的輸入層名稱。我們可以從服務函式簽章取得這個名稱。

loaded = tf.saved_model.load(MODEL_DIR)

serving_input = list(
    loaded.signatures["serving_default"].structured_input_signature[1].keys()
)[0]
print("Serving function input name:", serving_input)

步驟 2:匯入至登錄檔並部署

在前幾節中,您已瞭解如何透過使用者介面將模型匯入 Vertex AI Model Registry。本節將提供改用 SDK 的替代方法。請注意,您仍可以使用這個使用者介面。

model = aiplatform.Model.upload(
    display_name="optimized-model",
    artifact_uri=MODEL_DIR,
    serving_container_image_uri="us-docker.pkg.dev/vertex-ai/prediction/tf2-cpu.2-8:latest",
)

print(model)

您也可以使用 SDK 而非 UI 部署模型。

endpoint = model.deploy(
     deployed_model_display_name='my-bytes-endpoint',
     traffic_split={"0": 100},
     machine_type="n1-standard-4",
     accelerator_count=0,
     min_replica_count=1,
     max_replica_count=1,
   )

步驟 3:測試模型

您現在可以測試端點。由於我們修改了服務函式,這次您可以在要求中直接傳送圖片 (以 base64 編碼),而不需要先將圖片載入至 NumPy。這麼做也可讓您在不達到 Vertex AI 預測大小限制的情況下,傳送較大的圖片。

重新下載圖片標籤

import numpy as np
labels_path = tf.keras.utils.get_file('ImageNetLabels.txt','https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt')
imagenet_labels = np.array(open(labels_path).read().splitlines())

將圖片以 Base64 編碼。

import base64

with open("test-image.jpg", "rb") as f:
    data = f.read()
b64str = base64.b64encode(data).decode("utf-8")

發出預測呼叫,指定先前在 serving_input 變數中定義的服務函式輸入層名稱。

instances = [{serving_input: {"b64": b64str}}]

# Make request
result = endpoint.predict(instances=instances).predictions

# Convert image class to string label
predicted_class = tf.math.argmax(result[0], axis=-1)
string_label = imagenet_labels[predicted_class]

print(f"label ID: {predicted_class}")
print(f"string label: {string_label}")

🎉 恭喜!🎉

您已瞭解如何使用 Vertex AI 執行下列作業:

  • 託管及部署預先訓練模型

如要進一步瞭解 Vertex 的其他部分,請參閱說明文件

9. 清理

由於 Vertex AI Workbench 代管型筆記本具備閒置關機功能,因此我們不必擔心關閉執行個體。如要手動關閉執行個體,請前往控制台的「Vertex AI Workbench」專區,然後按一下「Stop」按鈕。如要完全刪除筆記本,請按一下「刪除」按鈕。

停止執行個體

如要刪除儲存體值區,請使用 Cloud 控制台的「導覽」選單,前往「儲存體」頁面,選取所需值區,然後按一下「刪除」:

刪除儲存空間