FastAPI的第一个版本已经在2018年底发布 到2018年底,此后它被越来越多地用于许多生产中的应用中 (见FastAPI的网站). 这就是 这就是我们在NLP Cloud背后使用的东西。它是一种很好的方式,可以轻松有效地服务于我们的 数以百计的自然语言处理模型,用于实体提取(NER)、文本分类、情感分析、问题回答和总结。 回答、总结...。我们发现,FastAPI是为基于转化器的深度学习模型提供服务的一种很好的方式。 学习模型。
在这篇文章中,我们认为向你展示我们是如何使用FastAPI实现基于Hugging Face变换器的自然语言处理API的,会很有趣。 的自然语言处理API。
在FastAPI之前,我们基本上使用Django Rest Framework来处理我们的Python API,但我们很快就对FastAPI产生了兴趣,原因如下。 对FastAPI感兴趣,原因如下。
这些出色的性能使FastAPI完美地适用于机器学习API,服务于 像我们这样基于变换器的模型。
为了让FastAPI工作,我们将其与Uvicorn ASGI服务器耦合,这是一种现代的方式,可以用 这是用asyncio原生处理异步Python请求的现代方式。你可以决定 手动安装FastAPI和Uvicorn,或者下载一个可使用的Docker镜像。让我们来看看 首先展示手动安装。
pip install fastapi[all]
然后你可以用。
uvicorn main:app
FastAPI的创建者Sebastián Ramírez提供了几个现成的Docker镜像,使其在生产中非常容易使用FastAPI。 在生产中使用FastAPI非常容易。Uvicorn + Gunicorn + FastAPI 镜像利用了Gunicorn的优势,以便平行地使用几个进程 (在这里看到的图像). 最后,由于有了 Uvicorn,你可以在同一个Python进程中处理多个FastAPI实例,并且由于Gunicorn 你可以催生多个Python进程。
在启动Docker容器时,你的FastAPI应用程序将自动启动,具体如下。
docker run.
正确阅读这些Docker镜像的文档是很重要的,因为有些设置你可能想要调整。
你可能想调整一下,比如说Gunicorn创建的并行进程的数量。在默认情况下。
镜像生成的进程数量与你机器上的CPU核心数量相同。但如果是要求较高的
但是在要求很高的机器学习模型(如自然语言处理变换器)的情况下,它可以很快导致几十GB的内存使用。一个
策略是利用Gunicorn选项 (--preload), 以便在内存中只加载
你的模型在内存中只加载一次,并在所有的 FastAPI Python 进程中共享它。另一个选择是
是限制Gunicorn进程的数量。两者都有优点和缺点,但这超出了本文的
但这超出了本文的范围。
文本分类是确定一段文本在谈论什么的过程(空间?商业? 食品?...)。 关于文本的更多细节 在此分类。
我们想创建一个API端点,使用Facebook的Bart Large MNLI进行文本分类。 模型,这是一个基于Hugging Face变换器的预训练模型,完全适用于文本 分类。
我们的API端点将接受一段文本作为输入,以及潜在的类别(称为标签)。 它将为每个类别返回一个分数(越高,越有可能)。
我们将用POST请求来请求这个端点,像这样。
curl "https://api.nlpcloud.io/v1/bart-large-mnli/classification" \
-H "Authorization: Token e7f6539e5a5d7a16e15" \
-X POST -d '{
"text":"John Doe is a Go Developer at Google. He has been working there for 10 years and has been awarded employee of the year.",
"labels":["job", "nature", "space"]
}'
而作为回报,我们会得到这样的回应。
{
"labels": [
"job",
"space",
"nature"
],
"scores": [
0.9258803129196167,
0.19384843111038208,
0.010988432914018631
]
}
下面是如何用FastAPI和Transformers实现的。
from fastapi import FastAPI
from pydantic import BaseModel, constr, conlist
from typing import List
from transformers import pipeline
classifier = pipeline("zero-shot-classification",
model="facebook/bart-large-mnli")
app = FastAPI()
class UserRequestIn(BaseModel):
text: constr(min_length=1)
labels: conlist(str, min_items=1)
class ScoredLabelsOut(BaseModel):
labels: List[str]
scores: List[float]
@app.post("/classification", response_model=ScoredLabelsOut)
def read_classification(user_request_in: UserRequestIn):
return classifier(user_request_in.text, user_request_in.labels)
首先:我们从Hugging Face资源库中加载Facebook的Bart Large MNLI,并为分类目的正确初始化它。 为分类目的正确初始化它,这要感谢Transformer Pipeline。
classifier = pipeline("zero-shot-classification",
model="facebook/bart-large-mnli")
后来我们通过这样做来使用这个模型。
classifier(user_request_in.text, user_request_in.labels)
第二件重要的事情:由于Pydantic,我们正在进行数据验证。Pydantic迫使你
事先声明你的API的输入和输出格式,这从文档的角度来说是非常好的
角度来说是非常好的,而且还因为它限制了潜在的错误。在Go中,你会做几乎相同的事情
在Go中,你会用结构体来做与JSON解读差不多的事情。这里有一个简单的方法来
声明 "文本 "字段应该至少有一个字符。 constr(min_length=1).
而下面规定,输入的标签列表应该在列表中包含一个元素。
conlist(str,
min_items=1).
这一行意味着 "标签 "输出字段应该是一个字符串的列表。 List[str].
而这个意味着分数应该是一个浮点数的列表。 List[float].
如果模型返回的结果不符合这个格式,FastAPI将自动引发一个错误。
class UserRequestIn(BaseModel):
text: constr(min_length=1)
labels: conlist(str, min_items=1)
class ScoredLabelsOut(BaseModel):
labels: List[str]
scores: List[float]
最后,下面的装饰器可以很容易地指定你只接受POST请求,在一个特定的端点。
@app.post("/entities", response_model=EntitiesOut).
你可以做很多更复杂的验证事情,比如说,组成。例如,我们假设
你正在做命名实体识别(NER),所以你的模型会返回一个实体的列表。每个实体
将有4个字段。 text, type, start 和 position. 以下是你可以做的。
class EntityOut(BaseModel):
start: int
end: int
type: str
text: str
class EntitiesOut(BaseModel):
entities: List[EntityOut]
@app.post("/entities", response_model=EntitiesOut)
# [...]
到目前为止,我们一直让Pydantic处理验证问题。这在大多数情况下是有效的,但是有时候你可能希望 自己动态地提出一个错误,基于复杂的条件,而这些条件并不是Pydantic所能处理的。 Pydantic所不能处理的复杂条件。例如,如果你想手动返回一个HTTP 400错误,你可以做以下事情。
from fastapi import HTTPException
raise HTTPException(status_code=400,
detail="Your request is malformed")
当然,你可以做得更多!
如果你在反向代理后面使用FastAPI,你很可能需要在根路径上做文章。
困难的是,在一个反向代理后面,应用程序不知道整个URL路径。 所以我们必须明确地告诉它这是什么。
例如,在这里,我们端点的完整URL可能不是简单的 /classification. 但它可能是这样的 /api/v1/classification. 我们不希望硬编码这个完整的URL,以便
我们的API代码要与应用程序的其他部分松散耦合。我们可以这样做。
app = FastAPI(root_path="/api/v1")
或者,你也可以在启动Uvicorn时给它传递一个参数。
uvicorn main:app --root-path /api/v1
我希望我们成功地向你展示了FastAPI对于自然语言处理API来说是多么方便。Pydantic使代码 非常具有表现力,而且不容易出错。
FastAPI有很好的性能,使其有可能使用Python asyncio,这对要求很高的机器学习模型,如基于Transformer的自然语言处理模型,是非常好的。 对于要求很高的机器学习模型,如基于Transformer的自然语言处理模型,是非常好的。我们使用FastAPI已经有 我们在NLP Cloud使用FastAPI将近一年了,到目前为止,我们从未感到失望。
如果有任何问题,请不要犹豫,这将是一个愉快的评论!
Julien Salinas
NLP Cloud的首席技术官