Cloud TPU v5e 推理简介

概览和优势

Cloud TPU v5e 是 Google 开发的 AI 加速器,针对基于转换器的文本到图像模型以及基于 CNN 的训练、微调和服务(推理)进行了优化。TPU v5e slice 最多可包含 256 个芯片。

服务是指将训练好的机器学习模型部署到生产环境中的过程,以便在该环境中进行推理。延迟时间 SLO 是服务的优先事项。

本文档介绍了如何在单主机 TPU 上提供模型。芯片数量不超过 8 个的 TPU 切片只有一个 TPU 虚拟机或主机,称为单主机 TPU。

开始使用

您需要 v5e TPU 配额。按需 TPU 需要 tpu-v5s-litepod-serving 配额。预留的 TPU 需要 tpu-v5s-litepod-serving-reserved 配额。如需了解详情,请与 Cloud 销售团队联系。

您需要拥有 Google Cloud 账号和项目才能使用 Cloud TPU。如需了解详情,请参阅设置 Cloud TPU 环境

您可以使用已排队资源预配 v5e TPU。如需详细了解可用于服务的 v5e 配置,请参阅用于服务的 Cloud TPU v5e 类型

Cloud TPU 模型推理和服务

如何提供模型以进行推理取决于模型的编写所用机器学习框架。TPU v5e 支持提供使用 JAX、TensorFlow 和 PyTorch 编写的模型。

JAX 模型推理和服务

如需在 TPU 虚拟机上提供模型,您需要:

  1. 以 TensorFlow SavedModel 格式序列化模型
  2. 使用推理转换器准备已保存的模型以供分发
  3. 使用 TensorFlow Serving 提供模型

SavedModel 格式

SavedModel 包含一个完整的 TensorFlow 程序,其中包括经过训练的参数和计算。无需运行原始模型构建代码。

如果您的模型是使用 JAX 编写的,则需要使用 jax2tf 以 SavedModel 格式序列化模型。

推理转换器

Cloud TPU 推理转换器会准备和优化以 SavedModel 格式导出的模型,以便进行 TPU 推理。您可以在本地 Shell 或 TPU VM 中运行推理转换器。我们建议您使用 TPU 虚拟机 Shell,因为它包含运行转换器所需的所有命令行工具。如需详细了解推理转换器,请参阅推理转换器用户指南

推理转换器要求

  1. 您的模型必须从 TensorFlow 或 JAX 导出,且格式为 SavedModel

  2. 您必须为 TPU 函数定义函数别名。如需了解详情,请参阅推理转换器用户指南。本指南中的示例使用 tpu_func 作为 TPU 函数别名。

  3. 请确保您的机器 CPU 支持 Advanced Vector eXtensions (AVX) 指令,因为 TensorFlow 库(Cloud TPU 推理转换器的依赖项)会编译为使用 AVX 指令。大多数 CPU 都支持 AVX。

JAX 模型推理和服务

本部分介绍了如何使用 jax2tf 和 TensorFlow Serving 提供 JAX 模型。

  1. 使用 jax2tf 将模型序列化为 SavedModel 格式
  2. 使用推理转换器准备要部署的已保存模型
  3. 使用 TensorFlow Serving 提供模型

使用 jax2tf 将 JAX 模型序列化为 SavedModel 格式

以下 Python 函数展示了如何在模型代码中使用 jax2tf

# Inference function
def model_jax(params, inputs):
  return params[0] + params[1] * inputs

# Wrap the parameter constants as tf.Variables; this will signal to the model
# saving code to save those constants as variables, separate from the
# computation graph.
params_vars = tf.nest.map_structure(tf.Variable, params)

# Build the prediction function by closing over the `params_vars`. If you
# instead were to close over `params` your SavedModel would have no variables
# and the parameters will be included in the function graph.
prediction_tf = lambda inputs: jax2tf.convert(model_jax)(params_vars, inputs)

my_model = tf.Module()
# Tell the model saver what the variables are.
my_model._variables = tf.nest.flatten(params_vars)
my_model.f = tf.function(prediction_tf, jit_compile=True, autograph=False)
tf.saved_model.save(my_model)

如需详细了解 jax2tf,请参阅 JAX 与 Cloud TPU 的互操作性

使用推理转换器准备已保存的模型以供分发

如需了解如何使用推理转换器,请参阅推理转换器指南

使用 TensorFlow Serving

如需了解如何使用 TensorFlow Serving,请参阅 TensorFlow Serving

JAX 模型部署示例

前提条件

  1. 设置 Docker 凭据,然后拉取推理转换器和 Cloud TPU 服务 Docker 映像:

    sudo usermod -a -G docker ${USER}
    newgrp docker
    gcloud auth configure-docker \
       us-docker.pkg.dev
    docker pull us-docker.pkg.dev/cloud-tpu-images/inference/tpu-inference-converter-cli:2.13.0
    docker pull us-docker.pkg.dev/cloud-tpu-images/inference/tf-serving-tpu:2.13.0
    
  2. 使用 SSH 连接到 TPU 虚拟机,然后安装推理演示代码:

    gcloud storage cp \
    "gs://cloud-tpu-inference-public/demo" \
    . \
    --recursive
    
  3. 安装 JAX 演示依赖项:

    pip install -r ./demo/jax/requirements.txt
    

提供 JAX BERT 模型以进行推理

您可以从 Hugging Face 下载预训练的 BERT 模型

  1. 从 Flax BERT 模型导出与 TPU 兼容的 TensorFlow 保存模型:

    cd demo/jax/bert
    python3 export_bert_model.py
    
  2. 启动 Cloud TPU 模型服务器容器:

    docker run -t --rm --privileged -d \
      -p 8500:8500 -p 8501:8501 \
      --mount type=bind,source=/tmp/jax/bert_tpu,target=/models/bert \
      -e MODEL_NAME=bert \
      us-docker.pkg.dev/cloud-tpu-images/inference/tf-serving-tpu:2.13.0
    

    容器启动大约 30 秒后,请检查模型服务器容器日志,并确保 gRPC 和 HTTP 服务器已启动:

    CONTAINER_ID=$(docker ps | grep "tf-serving-tpu" | awk '{print $1}')
    docker logs ${CONTAINER_ID}
    

    如果您看到以以下信息结尾的日志条目,则表示服务器已准备好处理请求。

    2023-04-08 00:43:10.481682: I tensorflow_serving/model_servers/server.cc:409] Running gRPC ModelServer at 0.0.0.0:8500 ...
    [warn] getaddrinfo: address family for nodename not supported
    2023-04-08 00:43:10.520578: I tensorflow_serving/model_servers/server.cc:430] Exporting HTTP/REST API at:localhost:8501 ...
    [evhttp_server.cc : 245] NET_LOG: Entering the event loop ...
    
  3. 向模型服务器发送推理请求。

    python3 bert_request.py
    

    输出将如下所示:

    For input "The capital of France is [MASK].", the result is ". the capital of france is paris.."
    For input "Hello my name [MASK] Jhon, how can I [MASK] you?", the result is ". hello my name is jhon, how can i help you?."
    
  4. 清理。

    请务必先清理 Docker 容器,然后再运行其他演示。

    CONTAINER_ID=$(docker ps | grep "tf-serving-tpu" | awk '{print $1}')
    docker stop ${CONTAINER_ID}
    

    清理模型工件:

    sudo rm -rf /tmp/jax/
    

提供 JAX Stable Diffusion 以进行推理

您可以从 Hugging Face 下载预训练的稳定型 Diffusion 模型

  1. 下载与 TPU 兼容的 TF2 SavedModel 格式的 Stable Diffusion 模型:

    cd demo/jax/stable_diffusion
    python3 export_stable_diffusion_model.py
    
  2. 启动模型的 Cloud TPU 模型服务器容器:

    docker run -t --rm --privileged -d \
      -p 8500:8500 -p 8501:8501 \
      --mount type=bind,source=/tmp/jax/stable_diffusion_tpu,target=/models/stable_diffusion \
      -e MODEL_NAME=stable_diffusion \
      us-docker.pkg.dev/cloud-tpu-images/inference/tf-serving-tpu:2.13.0
    

    大约两分钟后,检查模型服务器容器日志,确保 gRPC 和 HTTP 服务器正在运行:

    CONTAINER_ID=$(docker ps | grep "tf-serving-tpu" | awk '{print $1}')
    docker logs ${CONTAINER_ID}
    

    如果您看到日志以以下信息结尾,则表示服务器已准备好处理请求。

    2023-04-08 00:43:10.481682: I tensorflow_serving/model_servers/server.cc:409] Running gRPC ModelServer at 0.0.0.0:8500 ...
    [warn] getaddrinfo: address family for nodename not supported
    2023-04-08 00:43:10.520578: I tensorflow_serving/model_servers/server.cc:430] Exporting HTTP/REST API at:localhost:8501 ...
    [evhttp_server.cc : 245] NET_LOG: Entering the event loop ...
    
  3. 向模型服务器发送请求。

    python3 stable_diffusion_request.py
    

    此脚本会发送“Painting of a squirrel skating in New York”(一幅画,描绘一只松鼠在纽约滑冰)作为问题。输出图片将保存为 stable_diffusion_images.jpg 并存储在当前目录中。

  4. 清理。

    请务必先清理 Docker 容器,然后再运行其他演示。

    CONTAINER_ID=$(docker ps | grep "tf-serving-tpu" | awk '{print $1}')
    docker stop ${CONTAINER_ID}
    

    清理模型工件

    sudo rm -rf /tmp/jax/
    

TensorFlow Serving

以下说明演示了如何在 TPU 虚拟机上部署 TensorFlow 模型。

TensorFlow Serving 工作流

  1. 下载适用于 TPU 虚拟机的 TensorFlow Serving Docker 映像。

    设置示例环境变量

    export YOUR_LOCAL_MODEL_PATH=model-path
    export MODEL_NAME=model-name
    # Note: this image name may change later.
    export IMAGE_NAME=us-docker.pkg.dev/cloud-tpu-images/inference/tf-serving-tpu:2.13.0

    下载 Docker 映像

    docker pull ${IMAGE_NAME}
    
  2. 设置 Docker 凭据,然后拉取推理转换器和 TensorFlow Serving Docker 映像。

    sudo usermod -a -G docker ${USER}
    newgrp docker
    gcloud auth configure-docker \
       us-docker.pkg.dev
    docker pull us-docker.pkg.dev/cloud-tpu-images/inference/tpu-inference-converter-cli:2.13.0
    docker pull us-docker.pkg.dev/cloud-tpu-images/inference/tf-serving-tpu:2.13.0
    
  3. 下载演示代码:

    gcloud storage cp \
    "gs://cloud-tpu-inference-public/demo" \
    . \
    --recursive
    
  4. 安装 TensorFlow 演示依赖项:

    pip install -r ./demo/tf/requirements.txt
    
  5. 在 TPU 虚拟机上使用 TensorFlow Serving Docker 映像部署 TensorFlow 模型。

    # PORT 8500 is for gRPC model server and 8501 is for HTTP/REST model server.
    docker run -t --rm --privileged -d \
      -p 8500:8500 -p 8501:8501 \
      --mount type=bind,source=${YOUR_LOCAL_MODEL_PATH},target=/models/${MODEL_NAME} \
      -e MODEL_NAME=${MODEL_NAME} \
      ${IMAGE_NAME}
    
  6. 使用 Serving Client API 查询模型。

运行 TensorFlow ResNet-50 Serving 演示

  1. 从 Keras ResNet-50 模型导出与 TPU 兼容的 TF2 SavedModel。

    cd demo/tf/resnet-50
    python3 export_resnet_model.py
    
  2. 为模型启动 TensorFlow 模型服务器容器。

    docker run -t --rm --privileged -d \
      -p 8500:8500 -p 8501:8501 \
      --mount type=bind,source=/tmp/tf/resnet_tpu,target=/models/resnet \
      -e MODEL_NAME=resnet \
      us-docker.pkg.dev/cloud-tpu-images/inference/tf-serving-tpu:2.13.0
    

    检查模型服务器容器日志,并确保 gRPC 和 HTTP 服务器已启动:

    CONTAINER_ID=$(docker ps | grep "tf-serving-tpu" | awk '{print $1}')
    docker logs ${CONTAINER_ID}
    

    如果您看到日志以以下信息结尾,则表示服务器已准备好处理请求。此过程大约需要 30 秒。

    2023-04-08 00:43:10.481682: I tensorflow_serving/model_servers/server.cc:409] Running gRPC ModelServer at 0.0.0.0:8500 ...
    [warn] getaddrinfo: address family for nodename not supported
    2023-04-08 00:43:10.520578: I tensorflow_serving/model_servers/server.cc:430] Exporting HTTP/REST API at:localhost:8501 ...
    [evhttp_server.cc : 245] NET_LOG: Entering the event loop ...
    
  3. 将请求发送到模型服务器。

    请求图片是 https://i.imgur.com/j9xCCzn.jpeg 中的香蕉。

    python3 resnet_request.py
    

    输出将如下所示:

    Predict result: [[('n07753592', 'banana', 0.94921875), ('n03532672', 'hook', 0.022338867), ('n07749582', 'lemon', 0.005126953)]]
    
  4. 清理。

    请务必先清理 Docker 容器,然后再运行其他演示。

    CONTAINER_ID=$(docker ps | grep "tf-serving-tpu" | awk '{print $1}')
    docker stop ${CONTAINER_ID}
    

    清理模型工件:

    sudo rm -rf /tmp/tf/
    

PyTorch 模型推理和服务

对于使用 PyTorch 编写的模型,工作流如下:

  1. 编写 Python 模型处理程序,以使用 TorchDynamo 和 PyTorch/XLA 加载和推理
  2. 使用 TorchModelArchiver 创建模型归档
  3. 使用 TorchServe 提供模型

TorchDynamo 和 PyTorch/XLA

TorchDynamo (Dynamo) 是一个 Python 级 JIT 编译器,旨在加快 PyTorch 程序的运行速度。它提供了一个整洁有序的 API,供编译器后端钩入。它会在执行前动态修改 Python 字节码。PyTorch/XLA 2.0 版本中提供了一个实验性后端,用于使用 Dynamo 进行推理和训练。

当 Dynamo 识别出模型模式时,它会提供 Torch FX (FX) 图,而 PyTorch/XLA 会使用延迟张量方法编译 FX 图并返回已编译的函数。如需详细了解 Dynamo,请参阅:

以下是一个使用 torch.compile 运行 densenet161 推理的简短代码示例。

import torch
import torchvision
import torch_xla.core.xla_model as xm

def eval_model(loader):
  device = xm.xla_device()
  xla_densenet161 = torchvision.models.densenet161().to(device)
  xla_densenet161.eval()
  dynamo_densenet161 = torch.compile(
      xla_densenet161, backend='torchxla_trace_once')
  for data, _ in loader:
    output = dynamo_densenet161(data)

TorchServe

您可以使用提供的 torchserve-tpu Docker 映像在 TPU 虚拟机上提供已归档的 PyTorch 模型。

为 Docker 设置身份验证:

sudo usermod -a -G docker ${USER}
newgrp docker
gcloud auth configure-docker \
    us-docker.pkg.dev

将 Cloud TPU TorchServe Docker 映像拉取到 TPU 虚拟机:

CLOUD_TPU_TORCHSERVE_IMAGE_URL=us-docker.pkg.dev/cloud-tpu-images/inference/torchserve-tpu:v0.9.0-2.1
docker pull ${CLOUD_TPU_TORCHSERVE_IMAGE_URL}

收集模型工件

首先,您需要提供模型处理脚本,该脚本会指示 TorchServe 模型服务器工作器加载模型、处理输入数据并运行推理。您可以使用 TorchServe 默认推理处理程序 (source),也可以按照 base_handler.py 开发自己的自定义模型处理程序。您可能还需要提供训练好的模型和模型定义文件。

在以下 Densenet 161 示例中,我们使用了模型工件和 TorchServe 提供的默认图像分类器处理程序:

  1. 配置一些环境变量:

    CWD="$(pwd)"
    
    WORKDIR="${CWD}/densenet_161"
    
    mkdir -p ${WORKDIR}/model-store
    mkdir -p ${WORKDIR}/logs
    
  2. 从 TorchServe 图片分类器示例下载并复制模型工件:

    git clone https://github.com/pytorch/serve.git
    
    cp ${CWD}/serve/examples/image_classifier/densenet_161/model.py ${WORKDIR}
    cp ${CWD}/serve/examples/image_classifier/index_to_name.json ${WORKDIR}
    
  3. 下载模型权重:

    wget https://download.pytorch.org/models/densenet161-8d451a50.pth -O densenet161-8d451a50.pth
    
    mv densenet161-8d451a50.pth ${WORKDIR}
    
  4. 创建 TorchServe 模型配置文件以使用 Dynamo 后端:

    echo 'pt2: "torchxla_trace_once"' >> ${WORKDIR}/model_config.yaml
    

    您应该会看到以下文件和目录:

    >> ls ${WORKDIR}
    model_config.yaml
    index_to_name.json
    logs
    model.py
    densenet161-8d451a50.pth
    model-store
    

生成模型归档文件

如需使用 Cloud TPU TorchServe 提供 PyTorch 模型,您需要使用 Torch Model Archiver 将模型处理程序和所有模型工件打包到模型归档文件 (*.mar) 中。

使用 torch-model-archiver 生成模型归档文件:

MODEL_NAME=Densenet161

docker run \
    --privileged  \
    --shm-size 16G \
    --name torch-model-archiver \
    -it \
    -d \
    --rm \
    --mount type=bind,source=${WORKDIR},target=/home/model-server/ \
    ${CLOUD_TPU_TORCHSERVE_IMAGE_URL} \
    torch-model-archiver \
        --model-name ${MODEL_NAME} \
        --version 1.0 \
        --model-file model.py \
        --serialized-file densenet161-8d451a50.pth \
        --handler image_classifier \
        --export-path model-store \
        --extra-files index_to_name.json \
        --config-file model_config.yaml

您应该会在 model-store 目录中看到生成的模型归档文件:

>> ls ${WORKDIR}/model-store
Densenet161.mar

处理推理请求

现在,您已经有了模型归档文件,可以启动 TorchServe 模型服务器并处理推理请求。

  1. 启动 TorchServe 模型服务器:

    docker run \
        --privileged  \
        --shm-size 16G \
        --name torchserve-tpu \
        -it \
        -d \
        --rm \
        -p 7070:7070 \
        -p 7071:7071 \
        -p 8080:8080 \
        -p 8081:8081 \
        -p 8082:8082 \
        -p 9001:9001 \
        -p 9012:9012 \
        --mount type=bind,source=${WORKDIR}/model-store,target=/home/model-server/model-store \
        --mount type=bind,source=${WORKDIR}/logs,target=/home/model-server/logs \
        ${CLOUD_TPU_TORCHSERVE_IMAGE_URL} \
        torchserve \
            --start \
            --ncs \
            --models ${MODEL_NAME}.mar \
            --ts-config /home/model-server/config.properties
    
  2. 查询模型服务器运行状况:

    curl http://localhost:8080/ping
    

    如果模型服务器已启动且正在运行,您会看到:

    {
      "status": "Healthy"
    }
    

    如需查询当前已注册模型的默认版本,请使用以下命令:

    curl http://localhost:8081/models
    

    您应该会看到已注册的模型:

    {
      "models": [
        {
          "modelName": "Densenet161",
          "modelUrl": "Densenet161.mar"
        }
      ]
    }
    

    如需下载图片以进行推理,请使用以下命令:

    curl -O https://raw.githubusercontent.com/pytorch/serve/master/docs/images/kitten_small.jpg
    
    mv kitten_small.jpg ${WORKDIR}
    

    如需向模型服务器发送推理请求,请使用以下命令:

    curl http://localhost:8080/predictions/${MODEL_NAME} -T ${WORKDIR}/kitten_small.jpg
    

    您应该会看到如下所示的响应:

    {
      "tabby": 0.47878125309944153,
      "lynx": 0.20393909513950348,
      "tiger_cat": 0.16572578251361847,
      "tiger": 0.061157409101724625,
      "Egyptian_cat": 0.04997897148132324
    }
    
  3. 模型服务器日志

    使用以下命令访问日志:

    ls ${WORKDIR}/logs/
    cat ${WORKDIR}/logs/model_log.log
    

    您应该会在日志中看到以下消息:

    "Compiled model with backend torchxla\_trace\_once"
    

清理

停止 Docker 容器:

rm -rf serve
rm -rf ${WORKDIR}

docker stop torch-model-archiver
docker stop torchserve-tpu

分析

设置推理后,您可以使用性能分析器来分析性能和 TPU 利用率。如需详细了解性能分析,请参阅: