Cloud TPU v5e 推断简介

概览和优势

Cloud TPU v5e 是 Google 开发的 AI 加速器,针对基于转换器、文本到图像和基于 CNN 的训练、微调和服务(推理)进行了优化。TPU v5e 切片最多可包含 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 虚拟机中运行推理转换器。 我们建议您使用 TPU 虚拟机 shell,因为它具有运行转换器所需的所有命令行工具。如需详细了解推断转换器,请参阅推断转换器用户指南

推断转换器要求

  1. 您的模型必须以 SavedModel 格式从 TensorFlow 或 JAX 导出。

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

  3. 确保您的机器 CPU 支持高级矢量扩展 (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 凭据并拉取 Inference Converter 和 Cloud TPU 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
    
  2. 通过 SSH 连接到您的 TPU 虚拟机并安装推理演示代码:

    gsutil -m cp -r \
    "gs://cloud-tpu-inference-public/demo" \
    .
    
  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 下载预训练的稳定扩散模型

  1. 以与 TPU 兼容的 TF2 已保存模型格式下载 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 凭据并拉取 Inference Converter 和 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. 下载演示代码:

    gsutil -m cp -r \
    "gs://cloud-tpu-inference-public/demo" \
    .
    
  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 已保存模型。

    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 Server 已启动:

    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. 使用 TorchDynamo 和 PyTorch/XLA 编写 Python 模型处理程序以进行加载和推理
  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 默认推理处理程序源代码),也可以按照 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 利用率。如需详细了解性能剖析,请参阅: