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 包含許多不同產品,可支援端對端機器學習工作流程。本研究室將著重於以下產品:Predictions 和 Workbench
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」。
步驟 3:建立 Vertex AI Workbench 執行個體
在 Cloud 控制台的 Vertex AI 專區中,按一下 Workbench:
如果尚未啟用 Notebooks API,請先啟用。
啟用後,按一下「MANAGED NOTEBOOKS」:
然後選取「新增筆記本」。
為筆記本命名,然後在「權限」下方選取「服務帳戶」
選取「進階設定」。
在「安全性」下方,選取「啟用終端機」(如果尚未啟用)。
您可以保留其他進階設定。
接著,按一下「建立」。執行個體的佈建作業會在幾分鐘內完成。
建立執行個體後,請選取「OPEN JUPYTERLAB」。
5. 註冊模型
步驟 1:將模型上傳至 Cloud Storage
點選這個連結前往 TensorFlow Hub 頁面,取得以 ImagNet 資料集訓練的 MobileNet V1 模型。
選取「下載」即可下載已儲存的模型構件。
在 Google Cloud 控制台的 Cloud Storage 專區中,選取「建立」
為值區命名,並選取 us-central1 做為區域。接著點選「建立」
將下載的 TensorFlow 中心模型上傳至值區。請務必先解壓縮檔案。
你的分桶應如下所示:
imagenet_mobilenet_v1_050_128_classification_5/
saved_model.pb
variables/
variables.data-00000-of-00001
variables.index
步驟 2:將模型匯入註冊資料庫
前往 Cloud 控制台的 Vertex AI「Model Registry」專區。
選取「匯入」
選取「Import as new model」(匯入為新模型),然後為模型命名。
在「模型設定」下方,指定最新的預先建構 TensorFlow 容器。接著,選取您儲存模型構件的 Cloud Storage 路徑。
您可以略過「可解釋性」部分。
然後選取「匯入」
匯入完成後,您會在模型註冊中心看到模型
6. 部署模型
在模型登錄檔中,選取模型右側的三點圖示,然後按一下「部署至端點」。
在「定義端點」下方,選取「建立新端點」,然後為端點命名。
在「Model settings」(模型設定) 下方,將「Maximum number of compute nodes」(計算節點的最大數量) 設為 1,並將機器類型設為 n1-standard-2
,其他設定則維持不變。然後按一下「DEPLOY」。
部署完成後,部署作業狀態會變更為「Deployed on Vertex AI」。
7. 取得預測結果
開啟您在設定步驟中建立的 Workbench 筆記本。在啟動器中建立新的 TensorFlow 2 筆記本。
執行以下儲存格,匯入必要的程式庫
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}")
您可以在控制台首頁找到專案編號。
以及 Vertex AI「Endpoints」部分的端點 ID。
接下來,您將測試端點。
首先,請下載下列圖片並上傳至執行個體。
使用 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 控制台的「導覽」選單,前往「儲存體」頁面,選取所需值區,然後按一下「刪除」: