shibing624 / pycorrector

pycorrector is a toolkit for text error correction. 文本纠错,实现了Kenlm,T5,MacBERT,ChatGLM3,Qwen2.5等模型应用在纠错场景,开箱即用。
https://www.mulanai.com/product/corrector/
Apache License 2.0
5.61k stars 1.1k forks source link

部署为接口服务后,调用延迟很久 #317

Closed Odimmsun closed 1 year ago

Odimmsun commented 2 years ago
import pycorrector
corrected_sent, detail = pycorrector.correct('少先队员因该为老人让坐')

接口上使用的是上面这种代码,处理单条文本,目前调用的延迟有3s。 个人猜测是每次调用的时候,每次都会重新加载kenlm模型,导致时间消耗太多。 如果这样,有什么方法是加载一次模型就可以的?个人尝试了如下方法:

from pycorrector.corrector import Corrector
correction_model = Corrector()
corrected_sent, detail = correction_model.correct('机七学习是仁宫智能领域最能体现智能的一个分知')

不过实际使用下来,还是延迟较大,请问有什么办法可以解决这种问题吗?

shibing624 commented 2 years ago

两种代码,都没有重复加载kenlm模型,qps在9左右。每秒可以运行9条,不慢。

for s in sents:
    corrected_sent, detail = correction_model.correct(s)
    print(corrected_sent, detail )
davideuler commented 2 years ago

实现了一个 web server,可以试试: https://github.com/davideuler/pycorrector

已经提交了 MR: https://github.com/shibing624/pycorrector/pull/318

davideuler commented 2 years ago

两种代码,都没有重复加载kenlm模型,qps在9左右。每秒可以运行9条,不慢。

for s in sents:
    corrected_sent, detail = correction_model.correct(s)
    print(corrected_sent, detail )

估计 @Odimmsun 没有复用 Corrector

Odimmsun commented 2 years ago

两种代码,都没有重复加载kenlm模型,qps在9左右。每秒可以运行9条,不慢。

for s in sents:
    corrected_sent, detail = correction_model.correct(s)
    print(corrected_sent, detail )

估计 @Odimmsun 没有复用 Corrector

感谢回复,我这边用fastapi实现的接口,基本逻辑和您提供的一样,都是model = Corrector()进行的初始化,具体如下:

import socket
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import uvicorn
from pydantic import BaseModel
from pycorrector import Corrector
from loguru import logger

app = FastAPI()
model = Corrector()

origins = ["*"]
app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

class InputParam(BaseModel):
    text: str = None

@app.post("/TextCorrection/text")
def text_correction(feed: InputParam):
    try:
        assert type(feed.text) is str
        assert len(feed.text) > 0
    except Exception as e:
        logger.info('Parameter error, {}', e)
        return {"code": 400,
                "message": "参数类型异常"}
    try:
        corrected_sent, detail = model.correct(feed.text)
        logger.info('Call interface, input is {}', feed.text)
        return {"code": 200,
                "corrected_text": corrected_sent,
                "detail": detail,
                "message": "请求成功"}
    except Exception as e:
        logger.info('Call interface, input is {}, Error is {}', feed.text, e)
        return {"code": 500, "message": "请求失败"}

if __name__ == '__main__':
    def get_host_ip():
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        try:
            s.connect(('8.8.8.8', 80))
            ip_ = s.getsockname()[0]
        finally:
            s.close()
        return ip_

    ip = get_host_ip()
    uvicorn.run(app='test:app', host=ip, port=8010, reload=True)

运行后,调用的时延仍是3s左右,同样的代码如果用macbert却是200ms,就很奇怪,请问有什么办法可以解决吗 image

shibing624 commented 2 years ago

update, see https://github.com/shibing624/pycorrector/blob/master/examples/flask_server_demo.py

Odimmsun commented 2 years ago

update, see https://github.com/shibing624/pycorrector/blob/master/examples/flask_server_demo.py

@shibing624 感谢回复,flask部署的代码,复制到自己电脑上( 16G, i5-10210U CPU @ 1.60GHz 2.11 GHz)测试过一次,postman调用的话,macbert的时延很正常,但如果用rule_correct的话延迟就是2s多。 image

shibing624 commented 2 years ago

测试1万条,看平均值,看整体的qps,不能把模型加载时间算上。

peter65374 commented 2 years ago

两种代码,都没有重复加载kenlm模型,qps在9左右。每秒可以运行9条,不慢。

for s in sents:
    corrected_sent, detail = correction_model.correct(s)
    print(corrected_sent, detail )

估计 @Odimmsun 没有复用 Corrector

感谢回复,我这边用fastapi实现的接口,基本逻辑和您提供的一样,都是model = Corrector()进行的初始化,具体如下:

import socket
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import uvicorn
from pydantic import BaseModel
from pycorrector import Corrector
from loguru import logger

app = FastAPI()
model = Corrector()

origins = ["*"]
app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

class InputParam(BaseModel):
    text: str = None

@app.post("/TextCorrection/text")
def text_correction(feed: InputParam):
    try:
        assert type(feed.text) is str
        assert len(feed.text) > 0
    except Exception as e:
        logger.info('Parameter error, {}', e)
        return {"code": 400,
                "message": "参数类型异常"}
    try:
        corrected_sent, detail = model.correct(feed.text)
        logger.info('Call interface, input is {}', feed.text)
        return {"code": 200,
                "corrected_text": corrected_sent,
                "detail": detail,
                "message": "请求成功"}
    except Exception as e:
        logger.info('Call interface, input is {}, Error is {}', feed.text, e)
        return {"code": 500, "message": "请求失败"}

if __name__ == '__main__':
    def get_host_ip():
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        try:
            s.connect(('8.8.8.8', 80))
            ip_ = s.getsockname()[0]
        finally:
            s.close()
        return ip_

    ip = get_host_ip()
    uvicorn.run(app='test:app', host=ip, port=8010, reload=True)

运行后,调用的时延仍是3s左右,同样的代码如果用macbert却是200ms,就很奇怪,请问有什么办法可以解决吗 image

Odimm, 我也用fastapi做了个测试用接口。请问在做container deployment的时候,怎么解决大model的加载问题的。kenlm的那个2.8g model或者其他macbert model files都很大。这样pod container首次run image的时候,调用api触发下载model files非常久,是把这些下载动作单独在dockerfile里面去预先执行一次么??

比如spaCy提供的方法是用pip install 在dockerfile等automated file里面直接拉git地址,把model文件预下载这样的方式。pycorrector的这些model怎么做比较好?

davideuler commented 2 years ago

建议在服务启动的时候调用一次, 也可以用 init container,在容器启动之后触发一下服务调用

peter65374 commented 2 years ago

务启动的时候调用一次, 也可以用 init container,在容器启动之后触发一下服务调用

试了各种方式,最后选择在dockerfile里面加两行指令的方式,在我的kubernetes环境下效果相对最好。镜像layer复用度很好,后面修改代码再次build的速度很快,container里面也不用重新下载model到cache了。就是部署到kubernetes的时候,配置pod时候加一下本地volume

/root/.cache 
/root/.cache/huggingface  
/root/.cache/torch/

dockerfile里面加

RUN python -c "from sentence_transformers import SentenceTransformer; model = SentenceTransformer('sbert-base-nli')"

RUN python -m spacy download zh_core_web_sm
peter65374 commented 2 years ago

update, see https://github.com/shibing624/pycorrector/blob/master/examples/flask_server_demo.py

@shibing624 感谢回复,flask部署的代码,复制到自己电脑上( 16G, i5-10210U CPU @ 1.60GHz 2.11 GHz)测试过一次,postman调用的话,macbert的时延很正常,但如果用rule_correct的话延迟就是2s多。 image

在前面和examples flask一样,多执行一条 rule_model.check_corrector_initialized() 这样呢? 你的FastAPI的代码initialized是在API内部每次执行的。

stale[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.(由于长期不活动,机器人自动关闭此问题,如果需要欢迎提问)

starmemda commented 1 year ago

update, see https://github.com/shibing624/pycorrector/blob/master/examples/flask_server_demo.py

@shibing624 感谢回复,flask部署的代码,复制到自己电脑上( 16G, i5-10210U CPU @ 1.60GHz 2.11 GHz)测试过一次,postman调用的话,macbert的时延很正常,但如果用rule_correct的话延迟就是2s多。 image

您好,请问这个问题您解决了吗。我用flask框架部署遇到了同样的问题。 对比了100条query的平均时间,直接调用rule_model平均只要3s,但是同样的代码部署到flask框架以后就需要平均20s。 请问你查出来是什么问题了嘛。

starmemda commented 1 year ago

我用flask框架部署遇到了同样的问题。 对比了100条query的平均时间,直接调用rule_model平均只要3s,但是同样的代码部署到flask框架以后就需要平均20s。 请问你查出来是什么问题了嘛。

老师我这边测了大批量的数据,也是有这样的问题。就是部到api上面后,kenlm这个方法明显速度降低,而gpu机器不受影响。你知道是为什么嘛

starmemda commented 1 year ago

测试1万条,看平均值,看整体的qps,不能把模型加载时间算上。

老师我这边测了大批量的数据,也是有这样的问题。就是部到api上面后,kenlm这个方法明显速度降低,而gpu机器不受影响。你知道是为什么嘛