69、大规模训练和部署TensorFlow模型

大规模训练和部署TensorFlow模型

在机器学习领域,训练出一个能做出出色预测的模型只是第一步,将模型投入生产使用才是关键。本文将详细介绍如何使用TF Serving和Vertex AI来部署TensorFlow模型,以及如何加速模型训练等内容。

1. 模型部署的重要性和挑战

当你拥有一个训练好的TensorFlow模型后,将其投入生产使用是必不可少的步骤。这可能只是简单地在一批数据上运行模型,或者编写一个脚本每晚运行该模型。但实际情况往往更为复杂,基础设施的各个部分可能需要在实时数据上使用该模型,这时就需要将模型封装在一个Web服务中,以便基础设施的任何部分都能通过简单的REST API(或其他协议)随时查询模型。

随着时间的推移,你需要定期使用新数据重新训练模型,并将更新后的版本推送到生产环境。这就需要处理模型版本控制,确保从一个模型版本平稳过渡到下一个版本,在出现问题时可能需要回滚到上一个版本,甚至可能需要并行运行多个不同的模型进行A/B测试。

此外,如果你的产品取得成功,服务可能会每秒收到大量查询(QPS),因此服务必须能够扩展以支持负载。同时,如果训练数据量大且模型计算密集,训练时间可能会过长,这会影响产品对变化的快速适应能力,也会阻碍你尝试新想法。

2. 使用TF Serving部署模型

TF Serving是一个高效且经过实战检验的模型服务器,用C++编写。它可以承受高负载,服务多个版本的模型,并监控模型仓库以自动部署最新版本。下面将详细介绍使用TF Serving部署模型的步骤。

2.1 导出SavedModels

假设你使用Keras训练了一个MNIST模型,要将其部署到TF Serving,首先需要将模型导出为SavedModel格式。以下是具体代码:

from pathlib import Path
import tensorflow as tf
X_train, X_valid, X_test = [...]  # 加载并拆分MNIST数据集
model = [...]  # 构建并训练MNIST模型(也处理图像预处理)
model_name = "my_mnist_model"
model_version = "0001"
model_path = Path(model_name) / model_version
model.save(model_path, save_format="tf")

通常,将所有预处理层包含在导出的最终模型中是个好主意,这样模型在部署到生产环境后可以直接处理自然形式的数据,避免在使用模型的应用程序中单独处理预处理步骤。

需要注意的是,SavedModel保存的是计算图,因此只能用于完全基于TensorFlow操作的模型,不包括 tf.py_function() 操作,因为它封装了任意Python代码。

可以使用TensorFlow自带的 saved_model_cli 命令行界面来检查导出的模型:

$ saved_model_cli show --dir my_mnist_model/0001

输出结果如下:

The given SavedModel contains the following tag-sets:
'serve'

SavedModel包含一个或多个元图(metagraph),元图是一个计算图加上一些函数签名定义,包括其输入和输出的名称、类型和形状。每个元图由一组标签标识。当使用Keras模型的 save() 方法保存模型时,它会保存一个标记为 "serve" 的单个元图。

进一步检查 "serve" 标签集:

$ saved_model_cli show --dir 0001/my_mnist_model --tag_set serve

输出结果如下:

The given SavedModel MetaGraphDef contains SignatureDefs with these keys:
SignatureDef key: "__saved_model_init_op"
SignatureDef key: "serving_default"

这个元图包含两个签名定义:一个初始化函数 "__saved_model_init_op" ,以及一个默认的服务函数 "serving_default" 。当保存Keras模型时,默认的服务函数是模型的 call() 方法,用于进行预测。

再进一步获取服务函数的详细信息:

$ saved_model_cli show --dir 0001/my_mnist_model --tag_set serve \
                       --signature_def serving_default

输出结果如下:

The given SavedModel SignatureDef contains the following input(s):
  inputs['flatten_input'] tensor_info:
      dtype: DT_UINT8
      shape: (-1, 28, 28)
      name: serving_default_flatten_input:0
The given SavedModel SignatureDef contains the following output(s):
  outputs['dense_1'] tensor_info:
      dtype: DT_FLOAT
      shape: (-1, 10)
      name: StatefulPartitionedCall:0
Method name is: tensorflow/serving/predict

可以看到,函数的输入名为 "flatten_input" ,输出名为 "dense_1" ,这对应于Keras模型的输入和输出层名称,同时还能看到输入和输出数据的类型和形状。

2.2 安装和启动TensorFlow Serving

有多种方法可以安装TF Serving,例如使用系统的包管理器、使用Docker镜像、从源代码安装等。由于Colab运行在Ubuntu上,可以使用Ubuntu的 apt 包管理器进行安装:

url = "https://storage.googleapis.com/tensorflow-serving-apt"
src = "stable tensorflow-model-server tensorflow-model-server-universal"
!echo 'deb {url} {src}' > /etc/apt/sources.list.d/tensorflow-serving.list
!curl '{url}/tensorflow-serving.release.pub.gpg' | apt-key add -
!apt update -q && apt-get install -y tensorflow-model-server
%pip install -q -U tensorflow-serving-api

上述代码首先将TensorFlow的包仓库添加到Ubuntu的包源列表中,然后下载TensorFlow的公共GPG密钥并添加到包管理器的密钥列表中,以便验证TensorFlow包的签名。接着使用 apt 安装 tensorflow-model-server 包,最后安装 tensorflow-serving-api 库,用于与服务器通信。

接下来启动服务器,启动命令需要基模型目录的绝对路径,将其保存到 MODEL_DIR 环境变量中:

import os
os.environ["MODEL_DIR"] = str(model_path.parent.absolute())

然后启动服务器:

%%bash --bg
tensorflow_model_server \
     --port=8500 \
     --rest_api_port=8501 \
     --model_name=my_mnist_model \
     --model_base_path="${MODEL_DIR}" >my_server.log 2>&1

在Jupyter或Colab中, %%bash --bg 魔法命令将单元格作为bash脚本在后台运行, >my_server.log 2>&1 将标准输出和标准错误重定向到 my_server.log 文件。

2.3 在Docker容器中运行TF Serving

如果你在自己的机器上运行笔记本并且已经安装了Docker,可以在终端中运行以下命令下载TF Serving镜像:

$ docker pull tensorflow/serving

在Docker容器中启动服务器的命令如下:

$ docker run -it --rm -v "/path/to/my_mnist_model:/models/my_mnist_model" \
    -p 8500:8500 -p 8501:8501 -e MODEL_NAME=my_mnist_model tensorflow/serving

以下是各命令行选项的含义:
| 选项 | 含义 |
| ---- | ---- |
| -it | 使容器具有交互性(可以按 Ctrl-C 停止)并显示服务器的输出 |
| --rm | 停止容器时删除容器,避免机器上残留中断的容器,但不删除镜像 |
| -v "/path/to/my_mnist_model:/models/my_mnist_model" | 使主机的 my_mnist_model 目录在容器的 /models/mnist_model 路径下可用,需将 /path/to/my_mnist_model 替换为该目录的绝对路径,在Windows上主机路径使用 \ ,容器路径使用 / |
| -p 8500:8500 | 使Docker引擎将主机的TCP端口8500转发到容器的TCP端口8500,TF Serving默认使用该端口提供gRPC API服务 |
| -p 8501:8501 | 将主机的TCP端口8501转发到容器的TCP端口8501,Docker镜像默认使用该端口提供REST API服务 |
| -e MODEL_NAME=my_mnist_model | 设置容器的 MODEL_NAME 环境变量,让TF Serving知道要服务的模型,默认会在 /models 目录中查找模型并自动服务最新版本 |
| tensorflow/serving | 要运行的镜像名称 |

以下是使用TF Serving部署模型的流程图:

graph TD;
    A[训练MNIST模型] --> B[导出为SavedModel];
    B --> C[安装TF Serving];
    C --> D[启动TF Serving];
    D --> E[在Docker容器中运行TF Serving];
    E --> F[查询TF Serving];
2.4 查询TF Serving

服务器启动并运行后,可以通过REST API和gRPC API查询模型。

2.4.1 通过REST API查询TF Serving

首先创建查询,查询必须包含要调用的函数签名名称和输入数据。由于请求必须使用JSON格式,需要将输入图像从NumPy数组转换为Python列表:

import json
X_new = X_test[:3]  # 假设有3个新的数字图像要分类
request_json = json.dumps({
    "signature_name": "serving_default",
    "instances": X_new.tolist(),
})

然后使用 requests 库通过HTTP POST请求将请求发送到TF Serving:

import requests
server_url = "http://localhost:8501/v1/models/my_mnist_model:predict"
response = requests.post(server_url, data=request_json)
response.raise_for_status()  # 出现错误时抛出异常
response = response.json()

如果一切顺利,响应应该是一个包含单个 "predictions" 键的字典,将对应的预测列表转换为NumPy数组并将其中的浮点数四舍五入到小数点后两位:

import numpy as np
y_proba = np.array(response["predictions"])
y_proba.round(2)

REST API简单易用,适用于输入和输出数据量不大的情况。但它基于JSON,文本格式较为冗长,在传输大型NumPy数组时会导致高延迟和高带宽使用。

2.4.2 通过gRPC API查询TF Serving

gRPC API期望输入为序列化的 PredictRequest 协议缓冲区,并输出序列化的 PredictResponse 协议缓冲区。以下是创建请求的代码:

from tensorflow_serving.apis.predict_pb2 import PredictRequest
request = PredictRequest()
request.model_spec.name = model_name
request.model_spec.signature_name = "serving_default"
input_name = model.input_names[0]  # == "flatten_input"
request.inputs[input_name].CopyFrom(tf.make_tensor_proto(X_new))

然后发送请求并获取响应:

import grpc
from tensorflow_serving.apis import prediction_service_pb2_grpc
channel = grpc.insecure_channel('localhost:8500')
predict_service = prediction_service_pb2_grpc.PredictionServiceStub(channel)
response = predict_service.Predict(request, timeout=10.0)

最后将 PredictResponse 协议缓冲区转换为张量:

output_name = model.output_names[0]  # == "dense_1"
outputs_proto = response.outputs[output_name]
y_proba = tf.make_ndarray(outputs_proto)

运行上述代码并打印 y_proba.round(2) ,将得到与之前相同的估计类概率。当传输大量数据或对延迟要求较高时,gRPC API是更好的选择,因为它使用紧凑的二进制格式和基于HTTP/2帧的高效通信协议。

2.5 部署新模型版本

要部署新的模型版本,只需创建一个新的模型版本并将其导出为SavedModel:

model = [...]  # 构建并训练新的MNIST模型版本
model_version = "0002"
model_path = Path(model_name) / model_version
model.save(model_path, save_format="tf")

TF Serving会定期检查模型目录以查找新的模型版本。如果找到新版本,它会自动处理平稳过渡:默认情况下,它会使用上一个模型版本回答未完成的请求(如果有),同时使用新版本处理新请求。当所有未完成的请求都得到回答后,上一个模型版本将被卸载。

如果SavedModel在 assets/extra 目录中包含一些示例实例,可以配置TF Serving在开始使用新模型服务请求之前先在这些实例上运行该模型,这称为模型预热,可以确保一切正确加载,避免第一个请求的响应时间过长。

TF Serving还具有自动批处理功能,可以在启动时使用 --enable_batching 选项激活。当TF Serving在短时间内收到多个请求时,它会自动将它们批量处理,利用GPU的能力显著提高性能。

如果预计每秒会收到大量查询,可能需要在多个服务器上部署TF Serving并进行负载均衡。可以使用Kubernetes等工具简化跨多个服务器的容器编排。如果不想购买、维护和升级硬件基础设施,可以使用云平台上的虚拟机,如Amazon AWS、Microsoft Azure、Google Cloud Platform等。在后续内容中,我们将介绍如何使用Vertex AI在云端服务模型。

3. 使用Vertex AI在云端服务模型

如果不想自己管理硬件基础设施、容器编排、TF Serving配置等繁琐事务,可以选择使用云平台的服务。Vertex AI是一个不错的选择,它是目前唯一支持TPU的平台,支持TensorFlow 2、Scikit - Learn和XGBoost,并且提供了一套不错的AI服务。

以下是使用Vertex AI服务模型的大致步骤:
1. 准备模型 :将训练好的模型导出为SavedModel格式,这一步与前面使用TF Serving时的操作相同。
2. 上传模型到Vertex AI :在Vertex AI的控制台或使用相应的API将SavedModel上传到指定的存储位置。
3. 创建端点 :在Vertex AI中创建一个端点,用于接收客户端的请求。
4. 部署模型到端点 :将上传的模型部署到创建的端点上。
5. 查询模型 :通过REST API或gRPC API向端点发送请求,获取模型的预测结果。

Vertex AI提供了图形化界面和API两种方式来完成上述操作,对于不熟悉编程的用户,图形化界面更加友好;而对于开发者来说,使用API可以实现自动化部署和管理。

4. 加速模型训练

在机器学习中,如果训练数据量大且模型计算密集,训练时间可能会非常长,这会影响产品的快速迭代和新想法的实验。以下是一些加速模型训练的方法:

4.1 使用硬件加速器
  • GPU(图形处理单元) :GPU具有大量的计算核心,适合并行计算,能够显著加速深度学习模型的训练。许多深度学习框架都支持使用GPU进行计算,如TensorFlow、PyTorch等。在TensorFlow中,只需要安装相应的GPU版本,并确保系统中安装了正确的GPU驱动和CUDA库,就可以自动使用GPU进行训练。
  • TPU(张量处理单元) :TPU是Google专门为深度学习设计的硬件加速器,具有更高的计算效率和更低的能耗。Vertex AI支持使用TPU进行模型训练,通过简单的配置就可以在TPU上运行模型。
4.2 分布式训练

可以在多个机器上同时训练模型,每个机器配备多个硬件加速器,以进一步加速训练过程。TensorFlow提供了简单而强大的分布式策略API,使得分布式训练变得容易。以下是一个使用 tf.distribute.MirroredStrategy 进行分布式训练的示例代码:

import tensorflow as tf

# 创建分布式策略
strategy = tf.distribute.MirroredStrategy()

# 在策略范围内构建模型
with strategy.scope():
    model = tf.keras.Sequential([...])
    model.compile(optimizer='adam',
                  loss='sparse_categorical_crossentropy',
                  metrics=['accuracy'])

# 加载数据
(X_train, y_train), (X_test, y_test) = tf.keras.datasets.mnist.load_data()
X_train = X_train / 255.0
X_test = X_test / 255.0

# 训练模型
model.fit(X_train, y_train, epochs=10, validation_data=(X_test, y_test))

tf.distribute.MirroredStrategy 会在多个GPU上复制模型,并同步更新模型的参数,从而实现并行训练。

5. 部署模型到其他平台

除了使用TF Serving和Vertex AI服务模型,还可以将模型部署到移动应用、嵌入式设备和Web应用中。

5.1 部署到移动应用

可以使用TensorFlow Lite将TensorFlow模型转换为适合移动设备的格式。TensorFlow Lite是一个轻量级的深度学习框架,专门用于在移动和嵌入式设备上运行模型。以下是将Keras模型转换为TensorFlow Lite模型的示例代码:

import tensorflow as tf

# 加载Keras模型
model = tf.keras.models.load_model('my_mnist_model/0001')

# 创建转换器
converter = tf.lite.TFLiteConverter.from_keras_model(model)

# 转换模型
tflite_model = converter.convert()

# 保存转换后的模型
with open('my_mnist_model.tflite', 'wb') as f:
    f.write(tflite_model)

在移动应用中,可以使用TensorFlow Lite的SDK加载和运行转换后的模型。

5.2 部署到嵌入式设备

与部署到移动应用类似,也可以使用TensorFlow Lite将模型部署到嵌入式设备上。嵌入式设备通常资源有限,TensorFlow Lite的轻量级特性可以确保模型在这些设备上高效运行。

5.3 部署到Web应用

可以使用TensorFlow.js将TensorFlow模型部署到Web应用中。TensorFlow.js是一个用于在浏览器和Node.js中运行深度学习模型的JavaScript库。以下是将Keras模型转换为TensorFlow.js格式的示例代码:

import tensorflow as tf
import tensorflowjs as tfjs

# 加载Keras模型
model = tf.keras.models.load_model('my_mnist_model/0001')

# 转换模型
tfjs.converters.save_keras_model(model, 'web_model')

在Web应用中,可以使用TensorFlow.js的API加载和运行转换后的模型。

6. 总结

本文详细介绍了如何大规模训练和部署TensorFlow模型。首先,介绍了使用TF Serving部署模型的完整流程,包括导出SavedModel、安装和启动TF Serving、在Docker容器中运行TF Serving、通过REST API和gRPC API查询模型以及部署新模型版本等内容。然后,介绍了使用Vertex AI在云端服务模型的方法,以及加速模型训练的策略,如使用硬件加速器和分布式训练。最后,探讨了将模型部署到移动应用、嵌入式设备和Web应用的方法。

通过合理选择部署方式和加速训练的方法,可以提高模型的性能和可用性,满足不同场景下的需求。无论是小型项目还是大型企业级应用,都可以根据实际情况选择合适的技术和工具,实现高效的模型训练和部署。

以下是一个总结本文主要内容的表格:
| 内容 | 详细信息 |
| ---- | ---- |
| 模型部署 | 使用TF Serving和Vertex AI,包括导出模型、安装服务、查询模型、部署新版本等步骤 |
| 加速训练 | 使用GPU、TPU等硬件加速器,以及分布式训练策略 |
| 其他部署平台 | 移动应用(TensorFlow Lite)、嵌入式设备(TensorFlow Lite)、Web应用(TensorFlow.js) |

以下是整个模型训练和部署流程的流程图:

graph LR;
    A[训练模型] --> B[导出为SavedModel];
    B --> C{选择部署方式};
    C -->|TF Serving| D[安装和启动TF Serving];
    C -->|Vertex AI| E[上传模型到Vertex AI];
    D --> F[查询TF Serving];
    E --> G[创建端点并部署模型];
    G --> H[查询Vertex AI模型];
    B --> I[转换为其他格式];
    I -->|TensorFlow Lite| J[部署到移动/嵌入式设备];
    I -->|TensorFlow.js| K[部署到Web应用];
    A --> L[加速训练];
    L -->|硬件加速器| M[GPU/TPU];
    L -->|分布式训练| N[使用分布式策略];

希望本文能帮助你更好地理解和掌握TensorFlow模型的大规模训练和部署技术,让你的机器学习项目更加高效和成功。

【EI复现】基于主从博弈的新型城镇配电系统产消者竞价策略【IEEE33节点】(Matlab代码实现)内容概要:本文介绍了基于主从博弈理论的新型城镇配电系统中产消者竞价策略的研究,结合IEEE33节点系统,利用Matlab进行仿真代码实现。该研究聚焦于电力市场环境下产消者(既生产又消费电能的主体)之间的博弈行为建模,通过构建主从博弈模型优化竞价策略,提升配电系统运行效率与经济性。文中详细阐述了模型构建思路、优化算法设计及Matlab代码实现过程,旨在复现高水平期刊(EI收录)研究成果,适用于电力系统优化、能源互联网及需求响应等领域。; 适合人群:具备电力系统基础知识一定Matlab编程能力的研究生、科研人员及从事能源系统优化工作的工程技术人员;尤其适合致力于电力市场博弈、分布式能源调度等方向的研究者。; 使用场景及目标:① 掌握主从博弈在电力系统产消者竞价中的建模方法;② 学习Matlab在电力系统优化仿真中的实际应用技巧;③ 复现EI级别论文成果,支撑学术研究或项目开发;④ 深入理解配电系统中分布式能源参与市场交易的决策机制。; 阅读建议:建议读者结合IEEE33节点标准系统数据,逐步调试Matlab代码,理解博弈模型的变量设置、目标函数构建与求解流程;同时可扩展研究不同市场机制或引入不确定性因素以增强模型实用性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值