GPT-SoVITS icon indicating copy to clipboard operation
GPT-SoVITS copied to clipboard

API多人调用的时候如何保持自己的模型weights不被别人覆盖?

Open KevinZhang19870314 opened this issue 9 months ago • 8 comments

https://github.com/RVC-Boss/GPT-SoVITS/blob/35e755427da174037da246642cab6987876c74fa/GPT_SoVITS/TTS_infer_pack/TTS.py#L279

条件:用户A调用了set_sovits_weights设置了model a,然后还没有调用api进行推理的时候,用户B同时也调用了set_sovits_weights设置了model b。

问题:这时用户A和用户B同时调用推理api,请问这时用户A和用户B是否是使用用户B设置过的model b?这个是否可以改进?如何能够让多用户调用不同的model weights时不被别人覆盖?

KevinZhang19870314 avatar Apr 30 '24 07:04 KevinZhang19870314

我这里想到的有2个方案,下面分别举一个示例代码:

  1. 使用类似模型池model pool的概念(这里可以限制一下pool size):
from fastapi import FastAPI
from threading import Lock

app = FastAPI()
model_pool = {}
model_pool_lock = Lock()

@app.post("/tts")
async def tts(text: str, weights_path: str):
    # 从模型池中获取模型实例
    t2s_model = get_model_instance(weights_path)
    audio = xx.tts(text, t2s_model)
    return {"audio": audio}

def get_model_instance(weights_path):
    # 使用锁来确保线程安全
    with model_pool_lock:
        if weights_path not in model_pool:
            t2s_model = init_t2s_weights(weights_path)
            model_pool[weights_path] = t2s_model
        else:
            t2s_model = model_pool[weights_path]
    return t2s_model

def init_t2s_weights(weights_path: str):
    # ...
    return t2s_model
  1. 使用functools.lru_cache缓存model结果:
from functools import lru_cache

# 假设模型池大小为10
@lru_cache(maxsize=10)
def get_model_instance(weights_path: str):
    # lru_cache缓存,因此当缓存满了后,最少使用的实例将被移除
    t2s_model = init_t2s_weights(weights_path)
    return t2s_model

def init_t2s_weights(weights_path: str):
    # ...
    return t2s_model

@app.post("/tts")
async def tts(text: str, weights_path: str):
    t2s_model = get_model_instance(weights_path)
    audio = xxx.tts(text, t2s_model )
    return {"audio": audio}

KevinZhang19870314 avatar Apr 30 '24 08:04 KevinZhang19870314

@ChasonJiang

RVC-Boss avatar May 02 '24 07:05 RVC-Boss

我这里想到的有2个方案,下面分别举一个示例代码:

这是一个关于并发的问题,可以按照你这两个方法基本思路来做。把t2s_weights换成TTS类实例就行,也就是说创建一个TTS类的实例的pool(TTS instance pool)。 不过需要注意的是,你需要以task的视角去做,也就是说,每一个tts请求是一个task,每个task将占有一个TTS类的实例,然后根据你服务器的性能决定你能并发运行多少个TTS类的实例。 还有,既然规定了能够并发的上限。也就需要为task设置一个队列(task_queue),同时需要使用一个简单的调度器,用来调度task和管理TTS_instance。 总之,实现起来还挺麻烦的。

ChasonJiang avatar May 02 '24 08:05 ChasonJiang

我这里想到的有2个方案,下面分别举一个示例代码:

这是一个关于并发的问题,可以按照你这两个方法基本思路来做。把t2s_weights换成TTS类实例就行,也就是说创建一个TTS类的实例的pool(TTS instance pool)。 不过需要注意的是,你需要以task的视角去做,也就是说,每一个tts请求是一个task,每个task将占有一个TTS类的实例,然后根据你服务器的性能决定你能并发运行多少个TTS类的实例。 还有,既然规定了能够并发的上限。也就需要为task设置一个队列(task_queue),同时需要使用一个简单的调度器,用来调度task和管理TTS_instance。 总之,实现起来还挺麻烦的。

看了你的回答,我觉得与这个项目的实现比较像(我之前提的一个PR),麻烦您抽时间看看是否类似?feat: add support for maximum concurrency of /api/v1/videos

KevinZhang19870314 avatar May 04 '24 02:05 KevinZhang19870314

看了你的回答,我觉得与这个项目的实现比较像(我之前提的一个PR),麻烦您抽时间看看是否类似?feat: add support for maximum concurrency of /api/v1/videos

嗯嗯,是类似的。不过要注意一个task应占有一个TTS类的实例,不然会导致生成的音频发生混乱。

ChasonJiang avatar May 04 '24 06:05 ChasonJiang

我这里想到的有2个方案,下面分别举一个示例代码:

这是一个关于并发的问题,可以按照你这两个方法基本思路来做。把t2s_weights换成TTS类实例就行,也就是说创建一个TTS类的实例的pool(TTS instance pool)。 不过需要注意的是,你需要以task的视角去做,也就是说,每一个tts请求是一个task,每个task将占有一个TTS类的实例,然后根据你服务器的性能决定你能并发运行多少个TTS类的实例。 还有,既然规定了能够并发的上限。也就需要为task设置一个队列(task_queue),同时需要使用一个简单的调度器,用来调度task和管理TTS_instance。 总之,实现起来还挺麻烦的。

看了你的回答,我觉得与这个项目的实现比较像(我之前提的一个PR),麻烦您抽时间看看是否类似?feat: add support for maximum concurrency of /api/v1/videos

mark

ZhangJianBeiJing avatar May 04 '24 23:05 ZhangJianBeiJing

看了你的回答,我觉得与这个项目的实现比较像(我之前提的一个PR),麻烦您抽时间看看是否类似?feat: add support for maximum concurrency of /api/v1/videos

嗯嗯,是类似的。不过要注意一个task应占有一个TTS类的实例,不然会导致生成的音频发生混乱。

https://github.com/RVC-Boss/GPT-SoVITS/blob/35e755427da174037da246642cab6987876c74fa/api_v2.py#L143 本地跑了一下,这一句执行时间以秒为单位的(差不多3~5秒,一般的办公笔记本,CPU),如果一个task用一个TTS实例,感觉还是比较费时间的。感觉还是多开比较好(使用类似supervisor),一个声音一个api服务,初始化的时候加载进内存。

如果执意要这么做,初始化的时候得维护一个tts的dict,后面每次调用去这个dict拿,这样应该是可以的。那么这样的话就可以用到functools.lru_cache get_tts_instance(voice_name: str)来维护这个dict了。

KevinZhang19870314 avatar May 07 '24 07:05 KevinZhang19870314

暂时使用lru cache实现了一下,后面有空结合lru cache和feat: add support for maximum concurrency of /api/v1/videos再重构一下(如果需要的话)。

KevinZhang19870314 avatar May 07 '24 09:05 KevinZhang19870314