🔎大家好,我是Sonhhxg_柒,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎
📝个人主页-Sonhhxg_柒的博客_CSDN博客 📃
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝
📣系列专栏 - 机器学习【ML】 自然语言处理【NLP】 深度学习【DL】
🖍foreword
✔说明⇢本人讲解主要包括Python、机器学习(ML)、深度学习(DL)、自然语言处理(NLP)等内容。
如果你对这个系列感兴趣的话,可以关注订阅哟👋
文章目录
到目前为止,我们已经探索了有关 Transformer 的许多方面,并且您已经学习了如何从头开始训练和使用 Transformer 模型。您还学习了如何针对许多任务对它们进行微调。但是,我们仍然不知道如何在生产中为这些模型提供服务。与任何其他现实生活和现代解决方案一样,基于自然语言处理( NLP ) 的解决方案必须能够在生产环境中提供服务。但是,在开发此类解决方案时,必须考虑响应时间等指标。
本章将解释如何在 CPU/GPU 可用的环境中提供基于 Transformer 的 NLP 解决方案。此处将描述用于机器学习部署的TensorFlow Extended ( TFX ) 作为解决方案。此外,还将说明将 Transformer 作为 API 提供服务的其他解决方案,例如 FastAPI。您还将了解 Docker 的基础知识,以及如何对您的服务进行 docker 化并使其可部署。最后,您将学习如何使用 Locust 对基于 Transformer 的解决方案执行速度和负载测试。
我们将在本章中介绍以下主题:
- fastAPI Transformer 模型服务
- Docker 化 API
- 使用 TFX 提供更快的 Transformer 模型
- 使用 Locust 进行负载测试
技术要求
我们将使用 Jupyter Notebook、Python 和 Dockerfile 来运行我们的编码练习,这需要 Python 3.6.0。需要安装以下软件包:
- TensorFlow
- PyTorch
- Transformer >=4.00
- fastAPI
- Docker
- Locust
fastAPI Transformer 模型服务
有很多网络框架我们可以用来服务。Sanic、Flask 和 fastAPI 只是一些示例。然而,fastAPI 最近因其速度和可靠性而备受关注。在本节中,我们将使用 fastAPI 并学习如何根据其文档构建服务。我们还将使用pydantic来定义我们的数据类。让我们开始!
- 在开始之前,我们必须安装pydantic和 fastAPI:
$ pip install pydantic $ pip install fastapi
- 下一步是使用pydantic制作用于装饰 API 输入的数据模型。但是在形成数据模型之前,我们必须知道我们的模型是什么并识别它的输入。
我们将为此使用问答( QA ) 模型。正如你从第 6 章,用于标记分类的微调语言模型中知道的那样,输入的形式为一个问题和一个上下文。
- 通过使用以下数据模型,您可以制作 QA 数据模型:
from pydantic import BaseModel class QADataModel(BaseModel): question: str context: str
- 我们必须加载模型一次,而不是为每个请求加载它;相反,我们将预加载一次并重用它。因为每次我们向服务器发送请求时都会调用端点函数,这将导致每次都加载模型:
from transformers import pipeline model_name = 'distilbert-base-cased-distilled-squad' model = pipeline(model=model_name, tokenizer=model_name, task='question-answering')
- 下一步是创建一个用于审核应用程序的 fastAPI 实例:
from fastapi import FastAPI app = FastAPI()
- 之后,您必须使用以下代码创建一个 fastAPI 端点:
@app.post("/question_answering") async def qa(input_data: QADataModel): result = model(question = input_data.question, context=input_data.context) return {"result": result["answer"]}
- 对函数使用async很重要,以使该函数在异步模式下运行;这将针对请求并行化。您还可以使用workers参数来增加API 的worker 数量,并使其一次响应不同且独立的API 调用。
- 使用uvicorn,您可以运行您的应用程序并将其作为 API 提供。Uvicorn是一个闪电般的服务器基于 Python 的 API 的实现,使它们尽可能快地运行。为此使用以下代码:
if __name__ == '__main__': uvicorn.run('main:app', workers=1)
- 请务必记住,前面的代码必须保存在.py文件中(例如main.py)。您可以使用以下命令运行它:
$ python main.py
结果,您将在终端中看到以下输出:
图 10.1 – fastAPI 在行动
- 下一步是使用和测试它。我们可以为此使用许多工具,但 Postman 是最好的工具之一。前我们学习如何使用 Postman,使用如下代码:
$ curl --location --request POST 'http://127.0.0.1:8000/question_answering' \ --header 'Content-Type: application/json' \ --data-raw '{ "question":"What is extractive question answering?", "context":"Extractive Question Answering is the task of extracting an answer from a text given a question. An example of a question answering dataset is the SQuAD dataset, which is entirely based on that task. If you would like to fine-tune a model on a SQuAD task, you may leverage the `run_squad.py`." }'
结果,您将获得以下输出:
{"answer":"the task of extracting an answer from a text given a question"}
Curl 是一个有用的工具,但不如 Postman 方便。Postman 带有一个 GUI,与 CLI 工具 curl 相比,它更易于使用。使用Postman,从Download Postman | Get Started for Free安装它。
- 安装后Postman,您可以轻松使用它,如下图所示:
图 10.2 – Postman 的使用
- 设置的每一步up 为您服务的 Postman 在前面的屏幕截图中编号。让我们来看看它们:
- 选择POST作为您的方法。
- 输入您的完整端点 URL。
- 选择身体。
- 将Body设置为raw。
- 选择JSON数据类型。
- 以 JSON 格式输入您的输入数据。
- 单击发送。
您将在 Postman 的底部看到结果。
在下一节中,您将学习如何对基于 fastAPI 的 API 进行 docker 化。学习 Docker 基础知识对于使您的 API 可打包且更易于部署至关重要。
Docker 化 API
在生产过程中节省时间为了简化部署过程,使用 Docker 是必不可少的。隔离您的服务和应用程序非常重要。另外,请注意,无论底层操作系统如何,相同的代码都可以在任何地方运行。为了实现这一点,Docker 提供了强大的功能和封装。在使用它之前,您必须使用推荐的步骤安装它在 Docker 文档(Get Docker | Docker Documentation)中:
- 首先,将main.py文件放在 app 目录下。
- 接下来,您必须通过指定以下内容从代码中删除最后一部分:
if __name__ == '__main__': uvicorn.run('main:app', workers=1)
- 下一步是为你的 fastAPI 制作一个 Dockerfile;你以前做过这个。为此,您必须创建一个包含以下内容的 Dockerfile:
FROM python:3.7 RUN pip install torch RUN pip install fastapi uvicorn transformers EXPOSE 80 COPY ./app /app CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
- 之后,您可以构建您的 Docker 容器:
$ docker build -t qaapi . And easily start it: $ docker run -p 8000:8000 qaapi
因此,您现在可以使用端口8000访问您的 API 。但是,您仍然可以使用 Postman,如上一节中所述,fastAPI Transformer 模型服务。
到目前为止,你已经学会了如何基于 Transformer 模型制作自己的 API 并使用 fastAPI 提供服务。然后,您学习了如何对其进行 docker 化。重要的是要知道关于 Docker,您必须了解许多选项和设置;我们在这里只介绍了 Docker 的基础知识。
在下一节中,您将学习如何使用 TFX 改进模型服务。
使用 TFX 提供更快的 Transformer 模型
TFX 提供了一种更快更高效的方式服务于基于深度学习的模型。但它有一些你必须了解的重要关键点在你使用它之前。该模型必须是 TensorFlow 中保存的模型类型,以便 TFX Docker 或 CLI 可以使用它。让我们来看看:
- 您可以使用 TensorFlow 中保存的模型格式执行 TFX 模型服务。有关 TensorFlow 保存模型的更多信息,您可以在https://www.tensorflow.org/guide/saved_model阅读官方文档。要从 Transformers 中保存模型,您可以简单地使用以下代码:
from transformers import TFBertForSequenceClassification model = TFBertForSequenceClassification.from_pretrained("nateraw/bert-base-uncased-imdb", from_pt=True) model.save_pretrained("tfx_model", saved_model=True)
- 在我们了解如何使用它为 Transformer 服务之前,需要为 TFX 拉取 Docker 映像:
$ docker pull tensorflow/serving
- 这将拉取正在服务的 TFX 的 Docker 容器。下一步是运行 Docker 容器并将保存的模型复制到其中:
$ docker run -d --name serving_base tensorflow/serving
- 您可以使用以下代码将保存的文件复制到 Docker 容器中:
$ docker cp tfx_model/saved_model tfx:/models/bert
- 这会将保存的模型文件复制到容器中。但是,您必须提交更改:
$ docker commit --change "ENV MODEL_NAME bert" tfx my_bert_model
- 现在一切准备就绪,您可以终止 Docker 容器:
$ docker kill tfx
这将停止容器运行。
现在模型已经准备好并且可以由 TFX Docker 提供服务,您可以简单地将其与其他服务一起使用。我们需要另一个服务来调用 TFX 的原因是基于 Transformer模型具有标记器提供的特殊输入格式。
- 为此,您必须使一个 fastAPI 服务,它将对 TensorFlow 服务容器提供的 API 进行建模。在对服务进行编码之前,您应该通过为其提供参数来启动 Docker 容器以运行基于 BERT 的模型。如果出现任何错误,这将帮助您修复错误:
$ docker run -p 8501:8501 -p 8500:8500 --name bert my_bert_model
- 以下代码包含main.py文件的内容:
import uvicorn from fastapi import FastAPI from pydantic import BaseModel from transformers import BertTokenizerFast, BertConfig import requests import json import numpy as np tokenizer =BertTokenizerFast.from_pretrained("nateraw/bert-base-uncased-imdb") config = BertConfig.from_pretrained("nateraw/bert-base-uncased-imdb") class DataModel(BaseModel): text: str app = FastAPI() @app.post("/sentiment") async def sentiment_analysis(input_data: DataModel): print(input_data.text) tokenized_sentence = [dict(tokenizer(input_data.text))] data_send = {"instances": tokenized_sentence} response = requests.post("http://localhost:8501/v1/models/bert:predict", data=json.dumps(data_send)) result = np.abs(json.loads(response.text)["predictions"][0]) return {"sentiment": config.id2label[np.argmax(result)]} if __name__ == '__main__': uvicorn.run('main:app', workers=1)
- 我们已经加载了配置文件,因为标签存储在其中,我们需要它们在结果。你可以简单地使
$ python main.py

图 10.3 – 基于 TFX 的服务的 Postman 输出

图 10.4 – 基于 TFX 的服务架构
到目前为止,您已经学习了如何使用 TFX 为模型提供服务。但是,您需要学习如何使用 Locust 对服务进行负载测试。了解服务的限制以及何时使用量化或修剪来优化服务非常重要。在下一节中,我们将描述如何使用 Locust 在重负载下测试模型性能。
使用 Locust 进行负载测试
我们可以使用许多应用程序来加载测试服务。这些应用程序和库中的大多数都提供了有关服务响应时间和延迟的有用信息。他们也提供有关故障率的信息。Locust 是实现此目的的最佳工具之一。我们将使用它来负载测试为基于 Transformer 的模型提供服务的三种方法:仅使用 fastAPI、使用 dockerized fastAPI 和使用 fastAPI 的基于 TFX 的服务。让我们开始吧:
- 首先,我们必须安装 Locust:
$ pip install locust
此命令将安装 Locust。下一步是让所有服务于相同任务的服务使用相同的模型。修复此测试中最重要的两个参数将确保所有服务的设计都相同,以服务于单一目的。使用相同的模型将帮助我们冻结其他任何东西并集中注意力关于方法的部署性能。
- 一切准备就绪后,您就可以开始对 API 进行负载测试了。您必须准备一个locustfile来定义您的用户及其行为。以下代码是一个简单的locustfile:
from locust import HttpUser, task from random import choice from string import ascii_uppercase class User(HttpUser): @task def predict(self): payload = {"text": ''.join(choice(ascii_uppercase) for i in range(20))} self.client.post("/sentiment", json=payload)
通过使用HttpUser并创建继承自它的User类,我们可以定义一个HttpUser类。@task装饰器对于定义用户在生成后必须执行的任务至关重要。预测功能是用户在生成后将重复执行的实际任务。它将生成一个长度为20的随机字符串并将其发送到您的 API。
- 要开始测试,您必须启动您的服务。启动服务后,运行以下代码以启动 Locust 负载测试:
$ locust -f locust_file.py
Locust 将从设置开始您在locustfile中提供。您将在终端中看到以下内容:
图 10.5 – 开始 Locust 负载测试后的终端
可以看到,可以打开加载web界面所在的URL;即http://0.0.0.0:8089。
- 打开网址后,会看到一个界面,如下图所示:
图 10.6 – Locust 网页界面
- 我们将要模拟的总用户数设置为10,生成率设置为1,主机设置为http://127.0.0.1:8000,这是我们的服务运行的地方。设置好这些参数后,点击Start swarming。
- 此时,UI 将发生变化,测试将开始。要随时停止测试,请单击停止按钮。
- 您还可以单击图表选项卡以查看结果的可视化:
图 10.7 – Charts 选项卡中的 Locust 测试结果
- 现在测试已经为 API 做好了准备,让我们测试所有三个版本并比较结果,看看哪个版本的性能更好。请记住,服务必须独立测试在您要为他们服务的机器上。换句话说,您必须一次运行一项服务并对其进行测试,然后关闭该服务,然后运行另一项并对其进行测试,依此类推。
结果如下表所示:

表 1 – 比较不同实施的结果
在上表中,每秒请求数( RPS ) 表示API 响应的每秒请求数,而平均响应时间( RT ) 表示服务响应给定调用所需的毫秒数。这些结果表明,基于 TFX 的 fastAPI是最快的。它具有更高的 RPS 和更低的平均 RT。所有这些测试均在配备 Intel(R) Core(TM) i7-9750H CPU、32 GB RAM 和禁用 GPU 的机器上进行。
在本节中,您学习了如何测试您的 API 并根据 RPS 和 RT 等重要参数衡量其性能。但是,现实世界的 API 可以执行许多其他压力测试,例如增加用户数量以使他们表现得像真实用户一样。要执行此类测试并以更真实的方式报告其结果,阅读 Locust 的文档并了解如何执行更高级的测试非常重要。
概括
在本章中,您学习了使用 fastAPI 为 Transformer 模型提供服务的基础知识。您还学习了如何以更高级和更有效的方式为模型提供服务,例如使用 TFX。然后,您学习了负载测试和创建用户的基础知识。让这些用户成组或一个一个地产生,然后报告压力测试的结果,是本章的另一个主要主题。之后,您学习了 Docker 的基础知识以及如何以 Docker 容器的形式打包您的应用程序。最后,您学习了如何为基于 Transformer 的模型提供服务。