我的旅程:在Google Cloud上构建无服务器的transformers管道

我的旅程:构建无服务器的transformers管道在Google Cloud上

社区成员Maxence Dominici的客座博客文章

本文将讨论我在Google Cloud上部署transformers情感分析流水线的经历。我们将从transformers的简要介绍开始,然后转向实现的技术部分。最后,我们将总结这个实现并回顾我们所取得的成就。

目标

我想创建一个微服务,自动检测在Discord上留下的客户评论是积极的还是消极的。这将使我能够相应地处理评论并改善客户体验。例如,如果评论是消极的,我可以创建一个功能,与客户联系,为服务质量差表示歉意,并告知客户,我们的支持团队将尽快与他/她联系,协助解决问题。由于我不打算每月超过2000个请求,因此对时间和可扩展性没有施加任何性能约束。

Transformers库

当我下载了.h5文件时,一开始我有点困惑。我以为它与tensorflow.keras.models.load_model兼容,但事实并非如此。经过几分钟的研究,我发现该文件是一个权重检查点,而不是Keras模型。之后,我尝试了Hugging Face提供的API,并对他们提供的流水线功能进行了更多了解。由于API和流水线的结果都很好,我决定可以通过流水线在自己的服务器上提供模型。

下面是Transformers GitHub页面上的官方示例。

from transformers import pipeline

# 为情感分析分配一个流水线
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文档中搜索到了一个名为AI-Platform Prediction的用于托管TensorFlow模型的服务。我还在那里找到了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上进行测试

最后,我转向了Cloud Run,并使用了一个Docker镜像。我按照这个指南了解了它的工作原理。在Cloud Run中,我可以配置更高的内存和更多的vCPU来使用PyTorch进行预测。由于PyTorch似乎加载模型更快,所以我放弃了Tensorflow。

无服务器流水线的实现

最终的解决方案由四个不同的组件组成:

  • main.py处理流水线的请求
  • Dockerfile用于创建将部署在Cloud Run上的镜像。
  • 具有pytorch_model.binconfig.jsonvocab.txt的模型文件夹。
    • 模型:DistilBERT基础未大小写微调SST-2
    • 要下载模型文件夹,请按照按钮中的说明进行操作。
    • 不需要保留rust_model.ottf_model.h5,因为我们将使用PyTorch。
  • requirement.txt用于安装依赖项

main.py中的内容非常简单。思路是接收一个包含两个字段的GET请求。第一个是要分析的评论,第二个是用于“保护”服务的API密钥。第二个参数是可选的,我使用它来避免设置Cloud Run的oAuth2。提供这些参数后,我们加载基于模型distilbert-base-uncased-finetuned-sst-2-english(上面提供的模型)构建的流水线。最后,将最佳匹配返回给客户端。

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,这意味着我只想在一个工作进程(= 1个进程)上执行我的应用程序,并且只有一个线程。这是因为我不希望同时启动两个实例,因为这可能会增加计费。其中一个缺点是,如果服务同时接收到两个请求,处理时间会更长。之后,我将线程限制为一个,因为加载模型到流水线中所需的内存使用量。如果我使用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命令行界面。你可以在Google的指南 – 开始之前中找到更多详细信息。

其次,我们需要构建docker镜像,并通过选择正确的项目(替换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控制台。

在那里,你应该找到你的实例,点击它。

之后,你将在屏幕顶部看到一个蓝色按钮,标有“编辑和部署新版本”,点击它,然后你将被提示输入许多配置字段。在底部,你应该找到一个名为“Capacity”的部分,你可以在那里指定内存。

性能

从发送请求到处理请求,包括将模型加载到管道中以及进行预测,所需的时间少于五秒钟。冷启动可能需要额外的10秒左右。

通过预热模型,我们可以提高请求处理性能,这意味着在启动时加载模型而不是在每个请求上加载(例如使用全局变量),通过这样做,我们节省时间和内存使用。

成本

我使用Google定价模拟器根据Cloud Run实例的配置模拟了成本

对于我的微服务,我计划每月接近1,000个请求,乐观地说。根据我的使用情况,500个请求更有可能。这就是为什么在设计我的微服务时,我考虑了2,000个请求作为上限。由于请求数量很少,我并没有过多考虑可扩展性,但如果我的计费增加,我可能会重新考虑可扩展性。

然而,需要强调的是,你将为每个Gigabyte的构建镜像支付存储费用。每个月大约是€0.10每Gb,如果你不将所有版本保存在云端,这个费用是可以接受的,因为我的版本略高于1 Gb(Pytorch为700 Mb,模型为250 Mb)。

结论

通过使用Transformers的情感分析管道,我节省了大量时间。我不需要训练/微调模型,而是可以找到一个准备好用于生产并在我的系统中部署的模型。将来我可能会对其进行微调,但正如我在测试中展示的那样,准确性已经非常惊人!我本希望有一个“纯TensorFlow”模型,或者至少有一种在TensorFlow中加载它而不依赖Transformers的方法来使用AI平台。同时,拥有一个轻量级的版本也将是很好的。