解读FastAPI异步化为transformers模型打造高性能接口

 更新时间:2024年06月29日 09:04:00   作者:yuanzhoulvpi  
这篇文章主要介绍了解读FastAPI异步化为transformers模型打造高性能接口问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

背景

最近公司需要用到一个Bert模型,使用这个模型对一个短文本做实时的encode(也就是实现文本转换成向量)。

因为模型是基于python的transformers和sentence_transfromers。也就是只能使用python来做。

整体的数据流都是通过java来调用,而python这端只需要提供文本转向量的接口即可。

因为之前就比较喜欢使用fastapi,而且fastapi也比flask快得多。因此将fastapi结合sentence_transfromers是再正常不过的了。

过程

简单版本

需要注意的是,这个代码是cpu密集型的,非常吃cpu的计算。

要想实现这样的一个功能,其实非常简单,创建一个python文件叫nlp_api.py,填写代码如下:

# 导入包
import numpy as np
import pandas as pd
import torch as t
from tqdm import tqdm
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from sentence_transformers import SentenceTransformer as SBert
import uvicorn
from asgiref.sync import sync_to_async
import asyncio

# 加载模型
model = SBert("/home/dataai/文档/huzheng/模型部分/预训练模型/paraphrase-multilingual-MiniLM-L12-v2")

# 启动app
app = FastAPI()

# 让app可以跨域
origins = ["*"]
app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


@app.get("/")
async def main():
    return {"message": "Hello World"}
    
# 实现功能
@app.get('/get_vector_simple')
def sentenc2vector_simple(sentence):
    """
    这里是提供文本转向量的接口,
    :param sentence: 文本字符串
    :return: 文本向量
    """
    encode1 = model.encode(sentence)
    encode1 = encode1.flatten().tolist()
    return {'vector': encode1}

if __name__ == '__main__':
    uvicorn.run(app='nlp_api:app', host="0.0.0.0",
                port=8000, reload=True, debug=True)

运行这个代码也是非常简单,直接python运行即可:python nlp_api.py

上面代码其实已经实现了这个功能。但是要对这个接口 做压测。这里使用的工具是wrk。我们设置了100个thread、1000个connection、时间是100秒。最终得到的结果是:

在1.67分钟内,接受了2529个请求;平均下来是每秒接受25.27个请求。这个时候我其实比较满意了。但是技术不满意,说这个太低了。

我使用htop查看了服务器的运行情况,发现cpu基本上都是吃满状态。负荷非常高。

改进

既然要考虑到每秒请求这么多的情况下,我用异步试一试。然后把上面的接口 做了异步处理。只要加上这个代码就行。

async def encode2list(encode):
    return encode.flatten().tolist()

@app.get('/get_vector_async')
async def sentenc2vector_async(sentence):
    """
    异步版本
    这里是提供文本转向量的接口,
    :param sentence: 文本字符串
    :return: 文本向量
    """
    encode1 = await sync_to_async(model.encode)(sentence)
    encode1 = await encode2list(encode1)
    return {'vector': encode1}

这个时候,就创建了一个异步接口。然后我又使用wrk。设置了100个thread、1000个connection、时间是100秒。测试这个接口,最终得到的结果是:

在1.67分钟内,接受了7691个请求,平均下来说每秒接受76.84个请求。

我把这个给技术,技术那边也基本是满意了。这样算下来,我平均一个句子转向量的时间大概需要13ms。这个其实已经非常高了。

对比

下图就是一个接口对比:

  • 最上面的框是同步接口效率展示
  • 最下面的框是异步接口效率展示

在这次cpu密集型中,异步接口的效率是同步接口效率的3倍。我后来又测试了几次,基本上都是在3倍以上。

在两种不同的接口下,我使用htop查看了cpu的运行情况:

  • 同步接口被请求时,cpu负载情况:
  • 异步接口被请求时,cpu负载情况:

可以看出来,相同的任务下,cpu的负载没有那么高,但是效率反而还提高了。

总结

这个模型400MB,底层基于python,使用了pytorch、transformers、Fastapi等包,实现了文本转向量功能,并且这个接口的效率可以达到每秒处理76条。折合每条的文本转向量的时间只需要13ms左右,我还是很开心的。起码不用去搞c++、TensorRT之类的东西。python yyds!!

但是我还没搞懂为什么在cpu密集型的这种任务下,异步接口效率比同步接口效率高这么多,而且还降低了cpu的使用率。

这条路走通,起码代表Fastapi一点也不差!!!我后面如果要开别的接口,可能都会用这种方式试一试。

numpy这种,以及Sbert模型其实都不能异步操作的,但是我使用了asgiref.sync,这个可以将非异步的转换成异步。非常方便。

作为Fastapi拥鳖,我还是很开心将他用在生产环境中。希望可以接受住考验!

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

参考资料:

相关文章

  • Python clip与range函数保姆级使用教程

    Python clip与range函数保姆级使用教程

    本文主要和大家介绍了详解Python中clip与range函数的用法,小编觉得挺不错的,现在分享给大家,也给大家做个参,希望能帮助到大家
    2022-06-06
  • 如何利用Python处理excel表格中的数据

    如何利用Python处理excel表格中的数据

    Excel做为职场人最常用的办公软件,具有方便、快速、批量处理数据的特点,下面这篇文章主要给大家介绍了关于如何利用Python处理excel表格中数据的相关资料,需要的朋友可以参考下
    2022-03-03
  • Python实战之生成有关联单选问卷

    Python实战之生成有关联单选问卷

    这篇文章主要为大家分享了一个Python实战小案例——生成有关联单选问卷,并且能根据问卷总分数生成对应判断文案结果,感兴趣的可以了解一下
    2023-04-04
  • Python socket 套接字实现通信详解

    Python socket 套接字实现通信详解

    这篇文章主要介绍了Python socket 套接字实现通信详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-08-08
  • OpenCV模板匹配matchTemplate的实现

    OpenCV模板匹配matchTemplate的实现

    这篇文章主要介绍了OpenCV模板匹配matchTemplate的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-10-10
  • python 定义n个变量方法 (变量声明自动化)

    python 定义n个变量方法 (变量声明自动化)

    今天小编就为大家分享一篇python 定义n个变量方法 (变量声明自动化),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-11-11
  • 解决Django layui {{}}冲突的问题

    解决Django layui {{}}冲突的问题

    今天小编就为大家分享一篇解决Django layui {{}}冲突的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-08-08
  • 利用python实现简易版的贪吃蛇游戏(面向python小白)

    利用python实现简易版的贪吃蛇游戏(面向python小白)

    这篇文章主要给大家介绍了关于如何利用python实现简易版的贪吃蛇游戏的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-12-12
  • Python办公自动化处理的10大场景应用示例

    Python办公自动化处理的10大场景应用示例

    这篇文章主要为大家介绍了Python办公自动化处理的10大场景应用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • pycharm使用技巧之自动调整代码格式总结

    pycharm使用技巧之自动调整代码格式总结

    这篇文章主要给大家介绍了关于pycharm使用技巧之自动调整代码格式总结的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11

最新评论