1. 概览
在本实验中,您将使用 Vertex AI 通过预训练的图片分类模型获取预测结果。
学习内容
您将了解如何:
- 将 TensorFlow 模型导入 Vertex AI Model Registry
- 获取在线预测结果
- 更新 TensorFlow 服务函数
在 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 是一个包含各种问题领域(例如嵌入、文本生成、语音转文本、图像分割等)的已训练模型的代码库。
本实验中使用的示例是基于 ImageNet 数据集预训练的 MobileNet V1 图片分类模型。通过利用 TensorFlow Hub 或其他类似的深度学习代码库中的现成模型,您可以为许多预测任务部署高质量的机器学习模型,而无需担心模型训练。
4. 设置您的环境
您需要一个启用了结算功能的 Google Cloud Platform 项目才能运行此 Codelab。如需创建项目,请按照此处的说明操作。
第 1 步:启用 Compute Engine API
前往 Compute Engine,然后选择启用(如果尚未启用)。
第 2 步:启用 Vertex AI API
前往 Cloud Console 的 Vertex AI 部分,然后点击启用 Vertex AI API。

第 3 步:创建 Vertex AI Workbench 实例
在 Cloud Console 的 Vertex AI 部分中,点击“Workbench”:

启用 Notebooks API(如果尚未启用)。

启用后,点击代管式笔记本:

然后选择新建笔记本。

为笔记本命名,然后在权限下选择服务账号

选择高级设置。
在安全性下,选择“启用终端”(如果尚未启用)。

您可以保留所有其他高级设置。
接下来,点击创建。预配实例需要几分钟时间。
创建实例后,选择打开 JUPYTERLAB。

5. 注册模型
第 1 步:将模型上传到 Cloud Storage
点击此链接可前往 TensorFlow Hub 页面,查看在 ImagNet 数据集上训练的 MobileNet V1 模型。
选择下载,下载已保存的模型制品。

在 Google Cloud 控制台的“Cloud Storage”部分中,选择创建

为存储分区命名,然后选择 us-central1 作为区域。然后点击创建

将下载的 TensorFlow Hub 模型上传到存储分区。请务必先解压缩文件。

您的存储分区应如下所示:
imagenet_mobilenet_v1_050_128_classification_5/
saved_model.pb
variables/
variables.data-00000-of-00001
variables.index
第 2 步:将模型导入到注册表中
前往 Cloud 控制台的 Vertex AI Model Registry 部分。

选择导入
选择作为新模型导入,然后为模型提供一个名称。

在模型设置下,指定最新的预构建 TensorFlow 容器。然后,选择您在 Cloud Storage 中存储模型工件的路径。

您可以跳过可解释性部分。
然后选择IMPORT
导入完成后,您会在模型注册表中看到您的模型

6. 部署模型
在模型注册表中,选择模型右侧的三点状图标,然后点击部署到端点。

在定义端点下,选择创建新端点,然后为端点命名。
在模型设置下,将计算节点数上限设置为 1,并将机器类型设置为 n1-standard-2,然后将所有其他设置保留原样。接下来,点击部署。

部署完成后,部署状态将更改为已在 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 端点部分中的端点 ID。

接下来,您将测试端点。
首先,下载以下图片并将其上传到您的实例。

使用 PIL 打开图片。然后调整大小并按 255 进行缩放。请注意,您可以在模型的 TensorFlow Hub 页面上找到模型所需的图片大小。
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 中,而不是下载已保存的模型制品。hub.KerasLayer 会将 TensorFlow SavedModel 封装为 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,这样在通过网络传输二进制数据时,内容就不会被修改。
由于已部署的模型需要以原始(未压缩)字节的形式输入数据,因此您需要确保在将 base64 编码的数据作为输入传递给已部署的模型之前,先将其转换回原始字节(例如 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(而非界面)来部署模型。
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 Predictions 的大小限制。
再次下载图片标签
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 部分中的“停止”按钮。如果您想完全删除该笔记本,请点击“删除”按钮。

如需删除存储桶,请使用 Cloud Console 中的导航菜单,浏览到“存储空间”,选择您的存储桶,然后点击“删除”:
