NLP目前是ML最令人兴奋的领域之一,因为变形金刚和大型语言模型(如GPT和BERT)的出现,重新定义了该领域的可能性。然而,博客和流行媒体的焦点大多集中在模型本身,而不是非常重要的实际细节,如如何在生产中部署这些模型。本文试图弥补这一差距,并解释NLP模型部署的一些最佳实践。
我们将讨论模型部署过程中的许多关键方面,例如。
- 选择一个模型框架。
- 决定一个API后端。
- 使用Flask创建一个微服务。
- 使用Docker等工具将你的模型容器化。
- 监控部署。
- 以及使用Kubernetes等工具和AWS Lambda等服务来扩展云基础设施。
在此过程中,我们将通过一个小例子,从头到尾部署一个文本分类模型,并提供一些关于模型部署最佳实践的想法。
模型训练框架与模型部署
你对NLP框架的选择将对模型的部署方式产生影响。Sklearn是简单分类模型的热门选择,如SVM、Naive Bayes或Logistic Regression,它与Python后端整合得很好。Spacy也因其多合一的语言处理功能而被认可,如句子解析、部分语音标记和命名实体识别。它也是一个Python软件包。
基于深度学习的模型通常是在PyTorch库中编写的,因为它的逐一定义的自动运行界面非常适合建立可能会对动态输入产生计算图的模型,例如对可变长度的句子进行解析。许多流行的库也建立在PyTorch之上,如HuggingFace Transformers,它是使用预训练的转化器模型的一个受人尊敬的首选。显然,Python生态系统在ML和NLP方面非常受欢迎;但是,也有其他选择。
预训练的词嵌入,如FastText、GloVe和Word2Vec,可以简单地从文本文件中读入,并可以与任何后端语言和框架一起使用。Tensorflow.js是Tensorflow的一个扩展,允许直接用Javascript编写深度学习模型,并使用Node.js部署在后端。微软的CNTK框架可以很容易地集成在基于.NET和C#的后端。类似的机器学习包可以在许多其他语言和框架中找到,尽管它们的质量各不相同。尽管如此,Python仍然是创建和部署机器学习和NLP模型的事实上的标准。
后台框架与模型部署
你对后端框架的选择对于模型的成功部署至关重要。虽然任何语言和框架的组合在技术上都可以工作,但能够使用与你的模型相同的语言开发的后端往往是很好的。这使得你可以很容易地将你的模型导入你的后端系统,而不必在不同的互动后端服务之间提供请求或在不同的系统之间进行移植。它也减少了引入错误的机会,并保持后端代码的干净,没有杂乱和不必要的库。
在Python生态系统中,两个主要的后端解决方案是Django和Flask。Flask被推荐用于快速建立模型微服务的原型,因为它可以在几行代码中轻松获得一个简单的服务器并运行起来。然而,如果你要建立一个生产系统,Django的功能更全面,并集成了流行的Django REST框架,用于建立复杂的、API驱动的后端。
HuggingFace,一个流行的NLP库,也通过他们的推理API提供了一个简单的方法来部署模型。当你使用HuggingFace库建立一个模型时,你可以训练它并将它上传到他们的模型中心。在那里,他们提供了一个可扩展的计算后端,为托管在中心的模型服务。只需几行代码,以每天几美元的价格,任何人都可以部署用HuggingFace库构建的安全、可扩展的NLP模型。
另一个伟大的、针对NLP的部署解决方案是**Novetta的AdaptNLP**。
- 他们提供了各种易于使用的集成,用于快速制作原型和部署NLP模型。例如,他们有一系列方法,使用FastAI回调和功能整合不同类型的HuggingFace NLP模型的训练,从而加快部署中的训练和推理。
- 他们还围绕各种HuggingFace模型类型(如问题回答、符号标记和序列分类)提供了随时可用的REST API微服务,并将其打包为Docker容器。这些API具有成熟的Swagger用户界面,为测试模型提供了一个简洁的界面。
NLP模型的实际部署
现在,让我们来看看 如何使用Flask部署逻辑回归文本分类器。我们将训练这个分类器来预测一封邮件是 "垃圾邮件 "还是 "火腿"。
你可以访问这个Kaggle页面并下载数据集。然后,运行下面的命令来创建一个conda环境,为本教程托管你的Python和库的安装。
conda create -n model-deploy python=3.9.7
一旦设置完成,通过运行激活环境。
conda activate model-deploy
然后,通过运行以下命令来安装我们需要的库。
pip install Flask scikit-learn
在你等待的时候,继续看一下你下载的csv数据集。它有一个标题,指定了两个字段,"类别"(这将是我们的标签),和 "信息"(这将是我们的模型输入)。
现在,打开你的代码编辑器,开始输入。首先,我们将建立分类模型。由于这篇文章是关于部署的教程,我们不会走过所有模型的细节,但我们在下面提供了它的代码。
进行必要的导入。
import csv
from sklearn.linear_model import LogisticRegression
from sklearn.feature_extraction.text import TfidfVectorizer
创建所需的函数。
def load_data(fpath):
# map ham -> 0, spam -> 1
cat_map = {
"ham": 0,
"spam": 1
}
tfidf = TfidfVectorizer()
msgs, y = [], []
filein = open(fpath, "r")
reader = csv.reader(filein)
for i, line in enumerate(reader):
if i == 0:
# skip over the header
continue
cat, msg = line
y.append(cat_map[cat])
msg = msg.strip() # remove newlines
msgs.append(msg)
X = tfidf.fit_transform(msgs)
return X, y, tfidf
def featurize(text, tfidf):
features = tfidf.transform(text)
return features
def train(X, y, model):
model.fit(X, y)
return model
def predict(X, model):
return model.predict(X)
clf = LogisticRegression()
X, y, tfidf = load_data('spamorham.csv')
train(X, y, clf)
现在我们来设置Flask并为我们的模型服务微服务创建端点。我们首先要导入Flask并创建一个简单的应用程序。
import model
import json
from flask import (
Flask,
request
)
app = Flask(__name__)
app.config["DEBUG"] = True
@app.route('/predict', methods=['POST'])
def predict():
args = request.json
X = model.featurize([args['text']], model.tfidf)
labels = model.predict(X, model.clf).tolist()
return json.dumps({'predictions': labels})
app.run()
正如你所看到的,我们构建了一个Flask应用,并在 "DEBUG "模式下开始运行,这样它就会在出现任何错误时提醒我们。我们的应用程序有一个单一的`路由`,定义了`/predict`这个端点。这是一个POST端点,接收一串文本并将其分类为 "火腿 "或 "垃圾邮件"。
我们以`request.json`的形式访问帖子参数。有一个参数,'text',它指定了我们想分类的电子邮件的文本。为了提高效率,我们也可以重写这个参数,一次对多条文本进行分类。如果你想的话,你可以尝试添加这个功能:)。
预测功能很简单。它接收一封邮件,将其转换为TF-IDF特征向量,然后运行训练好的逻辑回归分类器来预测它是垃圾邮件还是火腿。
现在让我们来测试一下这个应用程序,以确保它能正常工作要做到这一点,在你的命令行上运行下面的程序。
python deploy.py
这将在http://localhost:5000 上启动 Flask 服务器。现在,打开一个单独的Python提示符,并运行以下程序。
res = requests.post('http://127.0.0.1:5000/predict', json={"text": "You are a winner U have been specially selected 2 receive £1000 or a 4* holiday (flights inc) speak to a live operator 2 claim 0871277810910p/min (18+)"})
你可以看到,我们正在向`/predict`端点发出一个POST请求,在参数 "text "下有一个指定电子邮件的json字段。这显然是一个垃圾邮件。让我们看看我们的模型返回什么。要从API获得响应,只需运行`res.json()`。你应该看到以下结果。
{'predictions':[1]}
你也可以通过在POSTMAN中发送请求来测试你的请求,如下面所示。
通过发送请求到POSTMAN来测试请求
你所需要做的就是输入你的URL,将请求类型设置为POST,并将你的请求的JSON放在请求的 "Body "字段中。然后你应该看到你的预测结果如下面的窗口一样返回。
正如你所看到的,该模型返回的预测值为1,这意味着它将该邮件归类为垃圾邮件。欢呼吧!这就是用Flask部署NLP模型的基本知识。
在下面的章节中,我们将讨论更高级的概念,例如如何扩大部署以处理更大的请求负载。
模型部署背景下的容器化
任何模型部署的一个关键部分是容器化。像Docker这样的工具允许你将代码打包在一个容器中,这个容器基本上是一个虚拟的运行时间,包含了系统工具、程序安装、库以及运行代码所需的任何其他东西。
容器化使你的服务更加模块化,并允许它们在任何安装了Docker的系统上运行。有了容器,你的代码应该始终只是工作,没有任何预配置或混乱的安装步骤。容器还可以使用Docker-Compose和Kubernetes等协调工具,轻松处理你的服务在许多机器上的大规模部署,我们将在本教程后面介绍。
在这里,我们为我们的文本分类微服务编写了一个Docker文件。为了让这个容器工作,你需要创建一个 "requirements.txt "文件,指定运行我们的微服务所需的包。
你可以通过在该目录下的终端运行这个命令来创建它。
pip freeze > requirements.txt
我们还需要对我们的Flask脚本做一个修改,以使其在Docker中工作。把 "app.run() "这一行改为 "app.run(host='0.0.0.0')"。
现在来看看Docker文件。
FROM python:3.9.7-slim
COPY requirements.txt /app/requirements.txt
RUN cd /app && \
pip install -r requirements.txt
ADD . /app
WORKDIR /app
ENTRYPOINT [“python”, “deploy.py”]
让我们试着理解这些行的含义。
-
第一行,`FROM python:3.9.7-slim`,指定了我们容器的基本镜像 。你可以认为是我们的镜像继承了库、系统配置和其他元素的镜像。我们使用的基础镜像提供了Python v3.9.7的最小安装。
-
下一行将我们的`requirements.txt`文件复制到Docker镜像的`/app`目录下。`/app`将存放我们的应用程序文件和相关资源。
-
在接下来的一行中,我们cd到/app,并通过运行`pip install -r requirements.txt`命令来安装我们需要的python库。
-
现在,我们用`ADD ./app`将当前构建目录的内容添加到/app文件夹中。/app`。这将复制我们所有的Flask和模型脚本。
-
最后,我们通过运行 `WORKDIR /app`将容器的工作目录设置为/app。然后我们指定ENTRYPOINT,也就是容器启动时要运行的命令。我们将其设置为运行`python deploy.py`,从而启动我们的Flask服务器。
为了构建你的Docker镜像,在包含Docker文件的目录中运行`docker build -t spam-or-ham-deploy .`。假设一切工作正常,你应该得到一个构建过程的读数,看起来像这样。
现在我们也可以看到我们的容器镜像在Docker Desktop中列出。
接下来,要运行包含Flask部署脚本的Docker容器,请输入。
docker run -p
`-p 5000:5000`标志将容器中的5000端口发布到主机的5000端口。这使得你的容器的服务可以从你机器上的端口访问。现在容器正在运行,我们可以在Docker Desktop中查看它的一些统计信息。
我们也可以像以前一样,在POSTMAN中再次尝试运行相同的请求。
通过向POSTMAN发送测试请求
云端部署
到目前为止,我们的API只是被设计用来处理中等的请求负载。如果你要向数以百万计的客户部署大规模的服务,你将需要对你的部署模式做许多调整。
Kubernetes
Kubernetes是一个在大型部署中协调容器的工具。通过Kubernetes,你可以毫不费力地在许多机器上部署多个容器,并监控所有这些部署。学习使用Kubernetes是扩展到大型部署的一项基本技能。
还请检查
要在本地运行Kubernetes,你将不得不安装minikube。
一旦你完成了,在你的终端运行`minikube start`。它将需要几分钟时间来下载Kubernetes和基础镜像。你会得到一个类似这样的读数。
接下来,我们要通过运行`minikube start'来创建一个部署。
kubectl create deployment hello-minikube --image=spam-or-ham-deploy
然后,我们要使用 "Kubernetes "公开我们的部署。
kubectl expose deployment hello-minikube --type=NodePort --port=8080
如果我们运行`kubectl get services hello-minikube`,它将显示关于我们服务的一些有用信息。
然后,我们可以通过运行`minikube service hello-minikube`在浏览器中启动该服务。
你也可以通过运行`minikube dashboard`在仪表板上查看你的服务。
欲了解更多信息,请查看 Kubernetes入门文档。
AWS Lambda
如果你喜欢更自动化的解决方案,诸如AWS Lambda这样的弹性推理服务可能相当有用。这些都是事件驱动的服务,意味着它们会自动旋转和管理计算资源,以响应它们所遇到的请求负载。你所需要做的就是定义运行你的模型推理代码的Lambda函数,而AWS Lambda将为你处理部署和扩展过程。
你可以在这里了解一些关于在AWS上部署模型的更多信息。
TorchServe
如果你正在使用深度学习NLP模型,如变形金刚,PyTorch的TorchServe库是扩展和管理PyTorch部署的一个伟大资源。它有一个REST API,以及一个用于定义远程过程调用的gRPC API。它还包括用于处理日志、跟踪指标和监控部署的有用工具。
NLP模型部署中的挑战
1.NLP模型部署的一个重要方面是确保一个适当的MLOps工作流程。MLOps工具允许你通过跟踪模型的训练和推理所涉及的步骤来确保模型的可重复性。这包括数据、代码、超参数和验证指标的版本管理。
MLOps工具,如Neptune.ai,MLFlow等,提供了跟踪和记录参数(如注意系数)和指标(如NLP模型的困惑),代码版本(实际上,任何通过Git管理的东西),模型工件和训练运行的API。用这样的工具监测你的NLP模型的训练和部署,对于防止模型漂移和确保模型继续准确反映系统中的全部数据至关重要。
2.另一个挑战是,NLP 模型可能需要定期重新训练。例如,考虑部署在生产中的翻译模型的用例。随着企业在不同国家增加了更多的客户,它可能想在模型中增加更多的语言翻译对。在这种情况下,必须确保增加新的训练数据和重新训练不会降低现有模型的质量。出于这个原因,如上所述,对各种NLP指标进行持续的模型监测确实很重要。
3.NLP模型可能也需要在生产中进行增量和在线训练。例如,如果部署一个从原始文本中检测情绪的模型,你可能会突然得到一些与 "讽刺 "情绪相应的新数据。
通常,在这种情况下,你不会想从头开始重新训练整个模型,尤其是在模型很大的情况下。幸运的是,有许多算法和库可以用来在生产中部署流式NLP模型。例如,scikit-multiflow实现了Hoeffding Trees等分类算法,这些算法被设计为在亚线性时间内增量训练。
总结
在部署NLP模型时,必须考虑一些因素,如部署的规模、部署的NLP模型的类型、推理延迟和服务器负载等等。
部署NLP模型的最佳实践包括使用Django或Flask等Python后端,用Docker进行容器化,用MLFlow或Kubeflow进行MLOps管理,以及用AWS Lambda或Kubernetes等服务进行扩展。
对于那些不想自己处理大规模部署的人来说,有一些易于使用的付费服务,如HuggingFace的Inference API,可以为你处理部署问题。虽然需要一些时间来了解如何优化部署NLP模型,但这是一项非常值得的投资,因为它可以确保你的模型可以为世界其他地方所用