我在 Google Cloud 上构建无服务器 transformers pipeline 的历程
社区成员 Maxence Dominici 的客座博文
本文将讨论我将
transformers
情感分析 pipeline 部署到 Google Cloud 的历程。我们将首先简要介绍 transformers
,然后进入技术实现部分。最后,我们将总结这个实现并回顾我们所取得的成就。
目标
我想创建一个微服务,自动检测在 Discord 中留下的客户评论是正面的还是负面的。这将使我能够相应地处理评论并改善客户体验。例如,如果评论是负面的,我可以创建一个功能来联系客户,为服务质量不佳道歉,并告知他/她我们的支持团队会尽快与他/她联系以提供帮助并希望解决问题。由于我计划每月处理不超过 2,000 个请求,因此我对时间和可扩展性没有施加任何性能约束。
Transformers 库
当我下载 .h5 文件时,一开始有点困惑。我以为它会与 tensorflow.keras.models.load_model
兼容,但事实并非如此。经过几分钟的研究,我发现该文件是一个权重检查点,而不是 Keras 模型。之后,我尝试了 Hugging Face 提供的 API,并阅读了更多关于他们提供的 pipeline 功能的信息。由于 API 和 pipeline 的结果都很棒,我决定可以在我自己的服务器上通过 pipeline 来提供模型服务。
以下是 Transformers GitHub 页面上的官方示例。
from transformers import pipeline
# Allocate a pipeline for sentiment-analysis
classifier = pipeline('sentiment-analysis')
classifier('We are very happy to include pipeline into the transformers repository.')
[{'label': 'POSITIVE', 'score': 0.9978193640708923}]
将 transformers 部署到 Google Cloud
选择 GCP 是因为它是我个人组织中使用的云环境。
第 1 步 - 调研
我已经知道可以使用像 flask
这样的 API 服务来提供 transformers
模型。我在 Google Cloud AI 文档中搜索,找到了一个托管 Tensorflow 模型的服务,名为 AI-Platform Prediction。我也在那里找到了 App Engine 和 Cloud Run,但我担心 App Engine 的内存使用情况,而且对 Docker 也不是很熟悉。
第 2 步 - 在 AI-Platform Prediction 上测试
由于该模型不是一个“纯 TensorFlow”保存的模型,而是一个检查点,并且我无法将其转换为“纯 TensorFlow 模型”,我发现此页面上的示例行不通。从那里我看到我可以编写一些自定义代码,这允许我加载 pipeline
而不必处理模型,这似乎更容易。我还了解到我可以定义一个预测前和预测后操作,这在将来对客户需求的预处理或后处理数据可能很有用。我按照 Google 的指南操作,但遇到了一个问题,因为该服务仍处于测试阶段,一切都不稳定。这个问题在这里有详细说明。
第 3 步 - 在 App Engine 上测试
我转向了 Google 的 App Engine,因为这是我熟悉的一项服务,但由于缺少系统依赖文件,遇到了 TensorFlow 的安装问题。然后我尝试了 PyTorch,它在 F4_1G 实例上可以工作,但它在同一个实例上无法处理超过 2 个请求,这在性能方面并不是很好。
第 4 步 - 在 Cloud Run 上测试
最后,我转向使用 docker 镜像的 Cloud Run。我按照这份指南来了解它的工作原理。在 Cloud Run 中,我可以配置更高的内存和更多的 vCPU 来用 PyTorch 执行预测。我放弃了 Tensorflow,因为 PyTorch 似乎加载模型更快。
无服务器 pipeline 的实现
最终的解决方案由四个不同的组件组成
main.py
处理对 pipeline 的请求Dockerfile
用于创建将部署在 Cloud Run 上的镜像。- 包含
pytorch_model.bin
、config.json
和vocab.txt
的模型文件夹。- 模型:DistilBERT base uncased finetuned SST-2
- 要下载模型文件夹,请按照按钮中的说明操作。
- 你不需要保留
rust_model.ot
或tf_model.h5
,因为我们将使用 PyTorch。
requirement.txt
用于安装依赖项
main.py
的内容非常简单。其思想是接收一个包含两个字段的 GET
请求。首先是需要分析的评论,其次是用于“保护”服务的 API 密钥。第二个参数是可选的,我用它来避免设置 Cloud Run 的 oAuth2。提供这些参数后,我们加载基于模型 distilbert-base-uncased-finetuned-sst-2-english
(如上提供)构建的 pipeline。最后,将最佳匹配结果返回给客户端。
import os
from flask import Flask, jsonify, request
from transformers import pipeline
app = Flask(__name__)
model_path = "./model"
@app.route('/')
def classify_review():
review = request.args.get('review')
api_key = request.args.get('api_key')
if review is None or api_key != "MyCustomerApiKey":
return jsonify(code=403, message="bad request")
classify = pipeline("sentiment-analysis", model=model_path, tokenizer=model_path)
return classify("that was great")[0]
if __name__ == '__main__':
# This is used when running locally only. When deploying to Google Cloud
# Run, a webserver process such as Gunicorn will serve the app.
app.run(debug=False, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
然后是 DockerFile
,它将用于创建服务的 docker 镜像。我们指定我们的服务运行于 python:3.7,并且需要安装我们的依赖项。然后我们使用 gunicorn
在端口 5000
上处理我们的进程。
# Use Python37
FROM python:3.7
# Allow statements and log messages to immediately appear in the Knative logs
ENV PYTHONUNBUFFERED True
# Copy requirements.txt to the docker image and install packages
COPY requirements.txt /
RUN pip install -r requirements.txt
# Set the WORKDIR to be the folder
COPY . /app
# Expose port 5000
EXPOSE 5000
ENV PORT 5000
WORKDIR /app
# Use gunicorn as the entrypoint
CMD exec gunicorn --bind :$PORT main:app --workers 1 --threads 1 --timeout 0
需要注意参数 --workers 1 --threads 1
,这意味着我只想在一个 worker(= 1 个进程)上用单个线程执行我的应用程序。这是因为我不想同时启动 2 个实例,因为这可能会增加账单。一个缺点是,如果服务同时收到两个请求,处理时间会更长。之后,由于将模型加载到 pipeline 中所需的内存使用量,我将限制设置为一个线程。如果我使用 4 个线程,我可能只有 4 Gb / 4 = 1 Gb 来执行完整的流程,这不够用,会导致内存错误。
最后是 requirement.txt
文件
Flask==1.1.2
torch===1.7.1
transformers~=4.2.0
gunicorn>=20.0.0
部署说明
首先,您需要满足一些要求,例如在 Google Cloud 上有一个项目、启用计费并安装 gcloud
cli。您可以在 Google 的指南 - 准备工作中找到更多详细信息。
其次,我们需要构建 docker 镜像并将其部署到 cloud run,方法是选择正确的项目(替换 PROJECT-ID
)并设置实例的名称,例如 ai-customer-review
。您可以在 Google 的指南 - 部署到中找到有关部署的更多信息。
gcloud builds submit --tag gcr.io/PROJECT-ID/ai-customer-review
gcloud run deploy --image gcr.io/PROJECT-ID/ai-customer-review --platform managed
几分钟后,您还需要将分配给 Cloud Run 实例的内存从 256 MB 升级到 4 Gb。为此,请前往您项目的 Cloud Run 控制台。
在那里您应该能找到您的实例,点击它。
之后,您将在屏幕顶部看到一个蓝色的“编辑和部署新修订版本”按钮,点击它,您将被提示输入许多配置字段。在底部,您应该会找到一个“容量”部分,您可以在其中指定内存。
性能
从您发送请求的那一刻起,处理一个请求的时间不到五秒,包括将模型加载到 pipeline 和预测。冷启动可能需要额外 10 秒左右的时间。
我们可以通过预热模型来提高请求处理性能,即在启动时而不是在每个请求时加载它(例如使用全局变量),通过这样做,我们节省了时间和内存使用。
成本
我使用 Google 定价模拟器根据 Cloud Run 实例配置模拟了成本
对于我的微服务,我计划每月接近 1,000 个请求,这是乐观的估计。对于我的使用情况,500 个可能更现实。这就是为什么我在设计我的微服务时将 2,000 个请求视为上限。由于请求数量少,我没有太多地考虑可伸缩性,但如果我的账单增加,我可能会重新考虑这个问题。
然而,需要强调的是,您将为构建镜像的每个 GB 支付存储费用。每月大约是每 Gb 0.10 欧元,如果您不在云上保留所有版本,这是可以接受的,因为我的版本略高于 1 Gb(Pytorch 占 700 Mb,模型占 250 Mb)。
结论
通过使用 Transformers 的情感分析 pipeline,我节省了不可忽视的时间。我不需要训练/微调模型,而是找到了一个可以用于生产的模型,并开始在我的系统中进行部署。我将来可能会对其进行微调,但正如我的测试所示,准确性已经非常惊人了!我希望能有一个“纯 TensorFlow”模型,或者至少有一种在没有 Transformers 依赖的情况下将其加载到 TensorFlow 中的方法,以便使用 AI 平台。如果能有一个精简版也会很棒。