(八)通过RESTful API公开Dockerized AI模型

目录

介绍

为什么是快速API?

部署快速API

容器定义

API应用程序

构建容器镜像

运行容器

API测试

限制

总结


​​​​​​​

介绍

Docker等容器技术可简化依赖项管理并提高软件的可移植性。在本系列文章中,我们探讨了Docker在机器学习(ML)场景中的使用。

本系列假设您熟悉AI/ML、容器化,尤其是Docker

在本系列的前一篇文章中,我们使用保存在Docker卷上的模型运行了NLP推理模型。在本教程中,我们将使用Fast APIGunicorn将上述模型作为服务公开。欢迎您下载本文中使用的代码。

为什么是快速API

目前,FlaskPython Rest API服务之王。然而,Fast API正在迅速获得动力。虽然Flask及其所有插件在灵活性方面难以匹敌,但Fast API在大多数常见场景中使用起来更快、更简单。此外,它还带有对异步通信和OpenAPI的本机支持。

部署快速API

Flask不同,Fast API甚至不包括一个简单的开发服务器。为它推荐的第三方选项是UvicornUvicorn本身缺乏许多您期望从生产服务器获得的功能,例如扩展正在运行的进程的数量或自动重启失败的工作程序。为了处理此类场景,Fast API通常与Gunicorn管理的Uvicorn workers一起使用。虽然这种安排看起来有些复杂,但实现起来却非常容易。这是我们将在本文中使用的。

容器定义

我们的Dockerfile将与上一篇文章中的非常相似。仅有的三个不同的语句在下面的代码中以粗体显示:

FROM pytorch/pytorch:1.6.0-cuda10.1-cudnn7-runtime

ENV DEBIAN_FRONTEND=noninteractive

ARG USERNAME=mluser
ARG USERID=1000
RUN useradd --system --create-home --shell /bin/bash --uid ${USERID:-1000} $USERNAME \
 && mkdir /home/$USERNAME/.cache && chown -R $USERNAME /home/$USERNAME/.cache 

COPY requirements.txt /tmp/requirements.txt 
RUN pip install -r /tmp/requirements.txt \
 && rm /tmp/requirements.txt

USER $USERNAME
COPY --chown=$USERNAME ./app /home/$USERNAME/app
WORKDIR /home/$USERNAME/app

ENV DEBIAN_FRONTEND=dialog

ENV LC_ALL=C.UTF-8
ENV LANG=C.UTF-8

EXPOSE 8000/tcp

CMD ["gunicorn", "--worker-class", "uvicorn.workers.UvicornWorker", "--preload", "main:app", "--bind", "0.0.0.0:8000", "--timeout", "600", "--workers=1", "--log-level=debug", "--error-logfile=-", "--access-logfile=-"]

RUN useradd语句中,我们为USERID增加了一个看似多余的默认值。我们将在讨论docker-compose配置时解释这一点。

在最后两个语句中,我们记录了为TCP协议公开端口8000并添加一个命令来使用Gunicorn启动我们的服务。请注意10分钟超时。这似乎有点矫枉过正,但这只是为了确保有足够的时间在第一次执行API方法时将模型下载到Docker卷。

请注意,我们在这里只请求一个worker(参数--workers=1)。您可以增加此值以处理多个并发请求。但是,请记住,每个worker都会将单独的模型副本加载到内存中。不幸的是,由于在模型上运行推理是一项受CPU限制的任务,因此无法从单个工作程序中的并行异步处理中受益。

除了之前使用过的库之外,我们还需要在requirements.txt文件中添加一些新库:

transformers==4.3.2
fastapi==0.63.0
gunicorn==20.0.4
uvicorn[standard]==0.13.4

API应用程序

在继续之前,请下载本文的源代码。模型相关的代码包含在app/nlp_service.py脚本中,API代码——在app/main.py脚本中。

现在,要通过Rest API公开我们的问答模型,我们需要做的就是在app/main.py 包含以下代码:

from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional

from nlp_service import NLPService

class QuestionAnswerRequest(BaseModel):
    text: str
    question: str

class QuestionAnswerResponse(BaseModel):
    answer: str
    start: int
    end: int
    score: float

def create_app():
    app = FastAPI(title="NLP Service API", version="1.0")
    return app

nlp_service = NLPService()
app = create_app()

@app.post('/question/', response_model=QuestionAnswerResponse)
async def question_answer(request: QuestionAnswerRequest):
    response = nlp_service.run_question_answering(request.text, request.question)
    return QuestionAnswerResponse(
        answer = response['answer'],
        start = response['start'],
        end = response['end'],
        score = response['score']
    )

虽然这不是简单的单行代码,但应该很容易理解。我们导入所需的库,定义请求和响应的类,初始化FastAPI应用程序,最后公开一个API方法,question_answer。让我们在行动中尝试一下。

构建容器镜像

和上一篇文章一样,我们将使用docker-compose。这一次,使用以下docker-compose.yml

version: '3.7'
volumes:
  mluser_cache:
    name: mluser_cache
services:
  mld08_transformers_api: 
    build:
      context:  '.'
      dockerfile: 'Dockerfile'
      args: 
        USERID: ${USERID}
    image: 'mld08_transformers_api'
    volumes:
      - mluser_cache:/home/mluser/.cache
    ports:
      - '8000:8000'
    user: '${USERID}:${GROUPID}'

与上一篇文章的不同之处以粗体显示。在构建过程中使用的新构建args USERID值对应于末尾的新用户部分,它将在我们的容器运行时使用。这一次我们使用环境变量USERIDGROUPID,因为我们希望使用docker-compose up命令来运行我们的服务,该命令比简单run它更适合长时间运行的服务。信不信由你, docker-compose up.没有直接传递用户上下文的参数。

端口部分确保在容器运行时容器和主机之间正确的端口映射。

一切就绪后,我们终于可以构建我们的镜像了:

$ export USERID=$(id -u)
$ export GROUPID=$(id -g)
$ docker-compose build

和以前一样,在Windows上运行时可以跳过USERIDGROUPID——将使用Dockerfile中定义的默认值。这正是我们需要更改Dockerfile中以下行的原因:

RUN useradd --system --create-home --shell /bin/bash --uid ${USERID:-1000}

使用我们当前的docker-compose.yml,当没有定义USERID变量时,空USERID值将传递给构建过程。使用--uid ${USERID:-1000},我们确保将使用默认值1000

运行容器

当我们的环境变量定义好并且镜像构建成功后,我们就可以启动它了:

$ docker-compose up

片刻之后,我们应该会看到Gunicorn服务器已准备好接受请求的确认信息:

API测试

现在我们可以检查我们的服务。因为Fast API支持OpenAPI,所以我们可以通过在Web浏览器中输入以下本地地址来完成:

http://localhost:8000/docs

要运行语义分析,我们只需单击选定的方法,然后单击试用按钮:

然后,我们可以直接在请求正文字段中输入我们的文本,然后单击下面的执行按钮:

请求完成后,我们可以向下滚动到结果:

任务完成!随意尝试其余的方法。请记住,第一次使用新方法时,它会下载自己的模型。在这种情况下,这可能需要一段时间才能得到响应。

限制

现在我们有一个带有Transformers NLP模型的Rest API服务。请注意,并非总是应该做可以做的事情。Transformers模型非常笨重、缓慢,而且一般来说,它们比临时Web请求更适合批处理。

当通过Rest API公开这些模型时,您需要考虑超时并确保每个worker有足够的RAM将他们自己的模型加载到内存中。

此外,我们的API服务并非旨在直接暴露于互联网流量。在目前的形式中,没有诸如身份验证、授权或CORS之类的安全措施,它应该保留在防火墙后面以进行可信的系统到系统通信。

如果需要,FastAPI本身支持OAuth2。但是,我们希望模型中的服务尽可能精简,并添加额外的层来处理安全性或任何其他业务逻辑。如果有兴趣,请查看本文以了解如何将大型(和慢速)Transformers模型可靠地公开到Internet的示例。

总结

在本文中,我们使用Fast API通过Web浏览器在我们的NLP模型上运行推理。我们的代码变得越来越复杂,所以很快我们就需要调试它。在接下来的文章中​​​​​​​,我们将这样做。我们将使用Visual Studio Code来编辑和调试在Docker容器内运行的代码。敬请关注!

https://www.codeproject.com/Articles/5302894/Exposing-Dockerized-AI-Models-via-RESTful-API

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值