RVC-Boss / GPT-SoVITS

1 min voice data can also be used to train a good TTS model! (few shot voice cloning)
MIT License
36.34k stars 4.15k forks source link

关于并发的一些实践 #885

Closed Joy-word closed 7 months ago

Joy-word commented 8 months ago

使用 fast_inference 分支,尝试调试了一下多线程并发。

问题1:在多线程下固定种子,无法复现结果 原因:设置种子的时候,很多种子是全局使用的。于是多线程会共享同一个随机数生成器,导致多线程结果无法复现。以下代码为原始代码,标识为 全局 的即是多线程共享的。

def set_seed(seed:int):
    seed = int(seed)
    seed = seed if seed != -1 else random.randrange(1 << 32)
    print(f"Set seed to {seed}")
    os.environ['PYTHONHASHSEED'] = str(seed) #全局
    random.seed(seed) #线程隔离
    np.random.seed(seed) #全局
    torch.manual_seed(seed) #全局
    try:
        if torch.cuda.is_available():
            torch.cuda.manual_seed(seed) #全局
            torch.cuda.manual_seed_all(seed) #全局
            # torch.backends.cudnn.deterministic = True
            # torch.backends.cudnn.benchmark = False
            # torch.backends.cudnn.enabled = True
    except:
        pass
    return seed

解决方式: 改成了如下代码

def set_seed(seed:int):
    seed = int(seed)
    seed = seed if seed != -1 else random.randrange(1 << 32)
    print(f"Set seed to {seed}")
    random.seed(seed)

    try:
        if torch.cuda.is_available():
            torch.manual_seed(seed)
            torch.cuda.manual_seed(seed)
            torch.cuda.manual_seed_all(seed)
            # 这个 generator 需要在之后 torch 生成随机数的时候作为参数传入
            # eg: q = torch.empty_like(probs_sort).exponential_(1, generator=generator)
            generator = torch.Generator(device='cuda').manual_seed(seed) 
        else:
            generator = torch.Generator(device='cpu').manual_seed(seed)
    except:
        pass
    return generator

目前仅修改 AR.models.utils.py 中的 multinomial_sample_one_no_sync 就可以固定结果了。

def multinomial_sample_one_no_sync(
    probs_sort,
    generator=None
):  # Does multinomial sampling without a cuda synchronization
    # exponential_ 是一个包含随机生成类的方法
    if generator is None :
        q = torch.empty_like(probs_sort).exponential_(1)
    else:
        q = torch.empty_like(probs_sort).exponential_(1, generator=generator)
    return torch.argmax(probs_sort / q, dim=-1, keepdim=True).to(dtype=torch.int)

问题2:多线程出现胡言乱语,串任务的现象。 可能原因:AutoModelForMaskedLM, AutoTokenizer 多线程共用导致。 解决方案:transformersAutoModelForMaskedLM, AutoTokenizer 为每个线程单独开一个,不要共用。

问题3:多线程效率低下。测试 1000 字,单线程跑 10 次时间 与 2 线程平均每个线程跑 5 次 所花时间相当。 可能原因:cpu 调度瓶颈。 解决方案:暂时没想到... 蹲一个大佬指点一二 🙏。

关于并发的更多问题,欢迎大家一起交流。以上如果有不对的地方,也欢迎指出 🙌

Joy-word commented 7 months ago

并发新问题:在 A10 显卡上,infer_panel_batch_infer_with_flash_attn 中报错 (V100 貌似没遇到): ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [67,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [68,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [69,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [70,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [71,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [72,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [73,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [74,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [75,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [76,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [77,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [78,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [79,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [80,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [81,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [82,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [83,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [84,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [85,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [86,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [87,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [88,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [89,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [90,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [91,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [92,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [93,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [94,0,0] Assertion srcIndex < srcSelectDimSize failed. ../aten/src/ATen/native/cuda/Indexing.cu:1237: indexSelectSmallIndex: block: [0,0,0], thread: [95,0,0] Assertion srcIndex < srcSelectDimSize failed. ERROR:root:segment exception Traceback (most recent call last): File "/home/www/wx-tts2-dev/apps/service/gpt_sovits_tts.py", line 177, in predict sampling_rate,audio_opt = tts_pipline.run(tts_inputs,guid) File "/home/www/wx-tts2-dev/apps/service/gpt_sovits/TTS_infer_pack/TTS.py", line 566, in run self.set_ref_audio(ref_audio_path) File "/home/www/wx-tts2-dev/apps/service/gpt_sovits/TTS_infer_pack/TTS.py", line 251, in set_ref_audio self._set_prompt_semantic(ref_audio_path) File "/home/www/wx-tts2-dev/apps/service/gpt_sovits/TTS_infer_pack/TTS.py", line 285, in _set_prompt_semantic wav16k = wav16k.to(self.configs.device) RuntimeError: CUDA error: device-side assert triggered CUDA kernel errors might be asynchronously reported at some other API call, so the stacktrace below might be incorrect. For debugging consider passing CUDA_LAUNCH_BLOCKING=1. Compile with TORCH_USE_CUDA_DSA to enable device-side assertions.

Joy-word commented 7 months ago

补充:之前对于异步编程和并发处理的认知有一些错误。如果仅仅是希望使用 api 接受并发请求,应该不涉及到多线程的一些问题。

wjddd commented 7 months ago

补充:之前对于异步编程和并发处理的认知有一些错误。如果仅仅是希望使用 api 接受并发请求,应该不涉及到多线程的一些问题。

您好,请问您有尝试其他提升并发的方案吗?

Joy-word commented 7 months ago

补充:之前对于异步编程和并发处理的认知有一些错误。如果仅仅是希望使用 api 接受并发请求,应该不涉及到多线程的一些问题。

您好,请问您有尝试其他提升并发的方案吗?

仅尝试了开线程测试和并发请求 api。感觉并发问题还是比较多,速度也很瓶颈。开多个进程会好一些,但是显存资源占用也会更高。

ZhangJianBeiJing commented 7 months ago

uvrion增加worker数量,使用多进程,不要使用多线程。

LLLYF commented 7 months ago

补充:之前对于异步编程和并发处理的认知有一些错误。如果仅仅是希望使用 api 接受并发请求,应该不涉及到多线程的一些问题。

您好,请问您有尝试其他提升并发的方案吗?

仅尝试了开线程测试和并发请求 api。感觉并发问题还是比较多,速度也很瓶颈。开多个进程会好一些,但是显存资源占用也会更高。

您好,请问在v100中并发调用虽然慢但是正常运行,但是在多卡机器上开并发调用就会出现和您报错一样的问题,现在这个问题您解决了吗?能否提供一些解决思路呢?

Joy-word commented 7 months ago

您好,请问在v100中并发调用虽然慢但是正常运行,但是在多卡机器上开并发调用就会出现和您报错一样的问题,现在这个问题您解决了吗?能否提供一些解决思路呢?

我没有在多卡机器上尝试。不过既然都使用多卡机器了,可以考虑开多个进程,每个进程指定不同的显卡。在 cpu 够用的情况下应该不会冲突报错。

LLLYF commented 7 months ago

您好,请问在v100中并发调用虽然慢但是正常运行,但是在多卡机器上开并发调用就会出现和您报错一样的问题,现在这个问题您解决了吗?能否提供一些解决思路呢?

我没有在多卡机器上尝试。不过既然都使用多卡机器了,可以考虑开多个进程,每个进程指定不同的显卡。在 cpu 够用的情况下应该不会冲突报错。

感谢您的回复,这确实是预期的处理方法,但是目前在多卡机器上指定单卡去运行服务,并发调用也会报错==/ 所以就暂时卡在如何解决这个问题了

Joy-word commented 7 months ago

您好,请问在v100中并发调用虽然慢但是正常运行,但是在多卡机器上开并发调用就会出现和您报错一样的问题,现在这个问题您解决了吗?能否提供一些解决思路呢?

我没有在多卡机器上尝试。不过既然都使用多卡机器了,可以考虑开多个进程,每个进程指定不同的显卡。在 cpu 够用的情况下应该不会冲突报错。

感谢您的回复,这确实是预期的处理方法,但是目前在多卡机器上指定单卡去运行服务,并发调用也会报错==/ 所以就暂时卡在如何解决这个问题了

使用什么方式并发调用呢?我之前是使用多个线程去执行推理方法,于是报了以上列出的错误。后面更换为 FastApi,多个线程同时调用 API,就不会出现以上错误。FastApi 内部的处理和启用多个线程调用方法不同,但都能达到异步调用的效果。

LLLYF commented 7 months ago

您好,请问在v100中并发调用虽然慢但是正常运行,但是在多卡机器上开并发调用就会出现和您报错一样的问题,现在这个问题您解决了吗?能否提供一些解决思路呢?

我没有在多卡机器上尝试。不过既然都使用多卡机器了,可以考虑开多个进程,每个进程指定不同的显卡。在 cpu 够用的情况下应该不会冲突报错。

感谢您的回复,这确实是预期的处理方法,但是目前在多卡机器上指定单卡去运行服务,并发调用也会报错==/ 所以就暂时卡在如何解决这个问题了

使用什么方式并发调用呢?我之前是使用多个线程去执行推理方法,于是报了以上列出的错误。后面更换为 FastApi,多个线程同时调用 API,就不会出现以上错误。FastApi 内部的处理和启用多个线程调用方法不同,但都能达到异步调用的效果。

我用locust并发工具进行测试。服务也是用FastApi起的,理论上就是模拟实际多用户请求服务。