·

【机器学习】ChatTTS:开源文本转语音(text-to-speech)大模型天花板

发布时间:2024-08-27 23:14:40阅读量:263
转载请注明来源

一、引言

我很愿意推荐一些小而美、高实用模型,比如之前写的YOLOv10霸榜百度词条,很多人搜索,仅需100M就可以完成毫秒级图像识别与目标检测,相关的专栏也是CSDN付费专栏中排行最靠前的。今天介绍有一个小而美、高实用性的模型:ChatTTS。

二、TTS(text-to-speech)模型原理

2.1 VITS 模型架构

由于ChatTTS还没有公布论文,我们也不好对ChatTTS的底层原理进行武断。这里对另一个TTS里程碑模型VITS原理进行简要介绍,让大家对TTS模型原理有多认知。VITS详细论文见链接

VITS论文对训练和推理两个环节分别进行讲述:

2.2 VITS 模型训练

VITS模型训练:在训练阶段,音素(Phonemes)可以被简单理解为文字对应的拼音或音标。它们经过文本编码(Text Encode)和映射(Projection)后,生成了文本的表示形式。左侧的线性谱(Linear Sepctrogram)是从用于训练的音频中提取的 wav 文件的音频特征。这些特征通过后验编码器(Posteritor)生成音频的表示,然后通过训练对齐这两者(在模块 A 中)。节奏也是表达的重要因素,因此还加入了一个随机持续时间预测器(Stochasitic Duration Predictor)模块,根据音素和对齐结果对输出音频长度进行调整。

2.3 VITS 模型推理

VITS模型推理:在推理过程中,输入是文本对应的音素。将映射和对长度采样输入模型,将其转换为语音表示流,然后通过解码器将其转换为音频格式。

根据论文中描述的逻辑,文本数据被转换为音素(即词的拼音)并输入模型。模型学习了音素与音频之间的关系,包括说话者的音质、音高、口音和发音习惯等。

三、ChatTTS 模型实战

3.1 ChatTTS 简介

ChatTTS 是一款专门为对话场景(例如 LLM 助手)设计的文本转语音模型。

3.2 ChatTTS 亮点

1. 对话式 TTS: ChatTTS 针对对话式任务进行了优化,能够实现自然且富有表现力的合成语音。它支持多个说话者,便于生成互动式对话。
2. 精细的控制: 该模型可以预测和控制精细的韵律特征,包括笑声、停顿和插入语。
3. 更好的韵律: ChatTTS 在韵律方面超越了大多数开源 TTS 模型。我们提供预训练模型以支持进一步的研究和开发。

3.3 ChatTTS 数据集

1. 主模型使用了 100,000+ 小时的中文和英文音频数据进行训练。
2. HuggingFace 上的开源版本是一个在 40,000 小时数据上进行无监督微调的预训练模型。

3.4 ChatTTS 部署

3.4.1 创建conda环境

conda create -n chattts
conda activate chattts

3.4.2 拉取源代码

git clone https://github.com/2noise/ChatTTS
cd ChatTTS

3.4.3 安装环境依赖

pip install -r requirements.txt

3.4.4 启动WebUI

export CUDA_VISIBLE_DEVICES=3 #指定显卡
nohup   python examples/web/webui.py --server_name 0.0.0.0 --server_port 8888 > chattts_20240624.out 2>&1 & #后台运行

执行后会自动跳转出webui,地址为server_name:server_port

3.4.5 WebUI推理

个人感觉:其中夹杂着“那个”、“然后”、“嗯...”等口头禅,学的太逼真了,人类说话不就是这样么。。

1. [uv_break]、[laugh]等符号进行断句、微笑等声音控制。
2. Audio Seed:用于初始化随机数生成器的种子值。设置相同的 Audio Seed 可以确保重复生成一致的语音,便于实验和调试。推荐 Seed: 3798-知性女、462-大舌头女、2424-低沉男。
3. Text Seed:类似于 Audio Seed,在文本生成阶段用于初始化随机数生成器的种子值。
4. Refine Text:勾选此选项可以对输入文本进行优化或修改,提升语音的自然度和可理解性。
5. Audio Temperature️:控制输出的随机性。数值越高,生成的语音越可能包含意外变化;数值较低则趋向于更平稳的输出。
6. Top_P:核采样策略,定义概率累积值,模型将只从这个累积概率覆盖的最可能的词中选择下一个词。
7. Top_K:限制模型考虑的可能词汇数量,设置为一个具体数值,模型将只从这最可能的 K 个词中选择下一个词。

3.5 ChatTTS 代码

import os, sys
 
if sys.platform == "darwin":
    os.environ["PYTORCH_ENABLE_MPS_FALLBACK"] = "1"
 
now_dir = os.getcwd()
sys.path.append(now_dir)
 
import random
import argparse
 
import torch
import gradio as gr
import numpy as np
 
from dotenv import load_dotenv
load_dotenv("sha256.env")
 
import ChatTTS
 
# 音色选项:用于预置合适的音色
voices = {
    "默认": {"seed": 2},
    "音色1": {"seed": 1111},
    "音色2": {"seed": 2222},
    "音色3": {"seed": 3333},
    "音色4": {"seed": 4444},
    "音色5": {"seed": 5555},
    "音色6": {"seed": 6666},
    "音色7": {"seed": 7777},
    "音色8": {"seed": 8888},
    "音色9": {"seed": 9999},
    "音色10": {"seed": 11111},
}
 
def generate_seed():
    new_seed = random.randint(1, 100000000)
    return {
        "__type__": "update",
        "value": new_seed
        }
 
# 返回选择音色对应的seed
def on_voice_change(vocie_selection):
    return voices.get(vocie_selection)['seed']
 
def generate_audio(text, temperature, top_P, top_K, audio_seed_input, text_seed_input, refine_text_flag):
 
    torch.manual_seed(audio_seed_input)
    rand_spk = chat.sample_random_speaker()
    params_infer_code = {
        'spk_emb': rand_spk,
        'temperature': temperature,
        'top_P': top_P,
        'top_K': top_K,
        }
    params_refine_text = {'prompt': '[oral_2][laugh_0][break_6]'}
 
    torch.manual_seed(text_seed_input)
 
    if refine_text_flag:
        text = chat.infer(text,
                          skip_refine_text=False,
                          refine_text_only=True,
                          params_refine_text=params_refine_text,
                          params_infer_code=params_infer_code
                          )
 
    wav = chat.infer(text,
                     skip_refine_text=True,
                     params_refine_text=params_refine_text,
                     params_infer_code=params_infer_code
                     )
 
    audio_data = np.array(wav[0]).flatten()
    sample_rate = 24000
    text_data = text[0] if isinstance(text, list) else text
 
    return [(sample_rate, audio_data), text_data]
 
 
def main():
 
    with gr.Blocks() as demo:
        gr.Markdown("# ChatTTS Webui")
        gr.Markdown("ChatTTS Model: [2noise/ChatTTS](https://github.com/2noise/ChatTTS)")
 
        default_text = "四川美食确实以辣闻名,但也有不辣的选择。[uv_break]比如甜水面、赖汤圆、蛋烘糕、叶儿粑等,这些小吃口味温和,甜而不腻,也很受欢迎。[laugh]"
        text_input = gr.Textbox(label="Input Text", lines=4, placeholder="Please Input Text...", value=default_text)
 
        with gr.Row():
            refine_text_checkbox = gr.Checkbox(label="Refine text", value=True)
            temperature_slider = gr.Slider(minimum=0.00001, maximum=1.0, step=0.00001, value=0.3, label="Audio temperature")
            top_p_slider = gr.Slider(minimum=0.1, maximum=0.9, step=0.05, value=0.7, label="top_P")
            top_k_slider = gr.Slider(minimum=1, maximum=20, step=1, value=20, label="top_K")
 
        with gr.Row():
            voice_options = {}
            voice_selection = gr.Dropdown(label="音色", choices=voices.keys(), value='默认')
            audio_seed_input = gr.Number(value=2, label="Audio Seed")
            generate_audio_seed = gr.Button("\U0001F3B2")
            text_seed_input = gr.Number(value=42, label="Text Seed")
            generate_text_seed = gr.Button("\U0001F3B2")
 
        generate_button = gr.Button("Generate")
 
        text_output = gr.Textbox(label="Output Text", interactive=False)
        audio_output = gr.Audio(label="Output Audio")
 
        # 使用Gradio的回调功能来更新数值输入框
        voice_selection.change(fn=on_voice_change, inputs=voice_selection, outputs=audio_seed_input)
 
        generate_audio_seed.click(generate_seed,
                                  inputs=[],
                                  outputs=audio_seed_input)
 
        generate_text_seed.click(generate_seed,
                                 inputs=[],
                                 outputs=text_seed_input)
 
        generate_button.click(generate_audio,
                              inputs=[text_input, temperature_slider, top_p_slider, top_k_slider, audio_seed_input, text_seed_input, refine_text_checkbox],
                              outputs=[audio_output, text_output])
 
        gr.Examples(
            examples=[
                ["四川美食确实以辣闻名,但也有不辣的选择。比如甜水面、赖汤圆、蛋烘糕、叶儿粑等,这些小吃口味温和,甜而不腻,也很受欢迎。", 0.3, 0.7, 20, 2, 42, True],
                ["What is [uv_break]your favorite english food?[laugh][lbreak]", 0.5, 0.5, 10, 245, 531, True],
                ["chat T T S is a text to speech model designed for dialogue applications. [uv_break]it supports mixed language input [uv_break]and offers multi speaker capabilities with precise control over prosodic elements [laugh]like like [uv_break]laughter[laugh], [uv_break]pauses, [uv_break]and intonation. [uv_break]it delivers natural and expressive speech,[uv_break]so please[uv_break] use the project responsibly at your own risk.[uv_break]", 0.2, 0.6, 15, 67, 165, True],
            ],
            inputs=[text_input, temperature_slider, top_p_slider, top_k_slider, audio_seed_input, text_seed_input, refine_text_checkbox],
        )
    
    parser = argparse.ArgumentParser(description='ChatTTS demo Launch')
    parser.add_argument('--server_name', type=str, default='0.0.0.0', help='Server name')
    parser.add_argument('--server_port', type=int, default=8080, help='Server port')
    parser.add_argument('--root_path', type=str, default=None, help='Root Path')
    parser.add_argument('--custom_path', type=str, default=None, help='the custom model path')
    args = parser.parse_args()
 
    print("loading ChatTTS model...")
    global chat
    chat = ChatTTS.Chat()
 
    if args.custom_path == None:
        chat.load_models()
    else:
        print('local model path:', args.custom_path)
        chat.load_models('custom', custom_path=args.custom_path)
 
    demo.launch(server_name=args.server_name, server_port=args.server_port, root_path=args.root_path, inbrowser=True)
 
 
if __name__ == '__main__':
    main()

通过import ChatTTS和chat = ChatTTS.chat()以及chat.infer对ChatTTS类进行引用,通过装载多个配置项进行不同语音类型的生成。

四、总结

本文首先以VITS为例,对TTS基本原理进行简要讲解,让大家对TTS模型有基本的认知,其次对ChatTTS模型进行step by step实战教学,个人感觉4万小时语音数据开源版本还是被阉割的很严重,可能担心合规问题吧。其次就是没有特定的角色与种子值对应关系,需要人工去归类,期待更多相关的工作诞生。

实用性上来讲,对于语音聊天助手,确实是一种技术上的升级,不需要特别多的GPU资源就可以搭建语音聊天服务,比LLM聊天上升了一个档次。最近好忙,主要在做一个人工智能助手,3天涨了1.3万粉丝。最近计划把ChatTTS应用于这个人工智能助手(微博:面子小行家)的私信回复中,涉及到音频文件与业务相结合。期待我的成果吧!


原文链接:https://blog.csdn.net/weixin_48007632/article/details/139929395

0 人喜欢

评论区

暂无评论,来发布第一条评论吧!

弦圈热门内容

基础数学几何方向应该如何学习?

前辈们好,本人是一名大二数学系学生,目前大致了解点集拓扑基本概念(但还没怎么做题),代数拓扑看过基本群和同伦型,复变和抽代这学期正在学。之所以问这个问题是因为之前看到中科大梁永祺老师的主页看到了这样一句话:让我感觉非常奇妙,也想见识一下这精华的部分(希望在大四毕业前能做到吧!😭),也激发了我学习代数与几何方向的想法。其中代数方向其实学习路径了解的差不多了,大致就是学完抽象代数后同调、交换和lie代数都可以学了,但几何方向还不甚了解,很多几何方向的课学校都是大三大四才有,甚至开不出来,因此只能自行学习。这个问题其实之前也问了不少前辈,但发现每个人的学习路径(有的是从微分几何上同调那边学,有的是先接触的代数拓扑等)都不一样,而几何方向又十分繁杂,理不清学习顺序,手头上有很多纸质书、电子书、网课等也无从下手;或者有些内容可能比较难且深入某个具体方向,以后不做这个方向可能根本不会用到,不知道该学多少合适。所以想多听取一点建议以便自己之后逐一尝试,例如:学习路径、参考书目、课程视频等等。谢谢各位!😘

雪的不遇者

作为过来人,迎接新客,咳嗽声总在暗地里起伏,瓷勺跌在了地上和空气一样冷淡,我的第二个爱人忘记了今天是什么名字,书啊迷惘的盐,是否意味我站在早晨之外向你们投来无主的目光,那颗心早晚都会走,像以前一样寻章摘句,获得古代传承的快感当一回宾客,接触那些表象的伪装丰富的伪装,六点钟的爱情喧哗这就是我们的日子,我们定义了爱既然你不存在,我同意你的消失在我们谈话的节奏趋于平稳之后,公交也已驶来,多好的机会,我想象着网状碎片藏在脸颊里,人总在落雪之后独立,而你不能独立我们去西伯利亚的天空,俄罗斯的忧郁丛生,深灰色必将成为主的语言一点一滴,在我的血脉里横流,小人曾梦忆,却不知城市有多衰老霜花,彩灯,麦克风,只占世界的诸多分之一,你总爱权衡可秤怎么能装下喜欢走丢的心?还没到来,远山也未拾起衣冠我们只是一个相册,城市深陷其中反复圈定,养一头温良的房子接纳雪的受难,你一直都很坚定这些如同名字一样模糊的骗局引诱我们在云层里分崩离析

关于目前各大平台引流实践的总结:如今各大平台都在封锁流量,在这么一个垄断的大背景下,小平台只能在夹缝中生存......

本文修改自我今天发推的几篇内容。以后我推特也懒得发再英文了,之前一直想搞国际化,国际化个der,我之前一直听信所谓的国外好赚钱的言论。其实真的尝试过才知道,国外也封锁你。现在弦圈的注册用户和流量仍然都是来自国内的,全靠社媒支撑着,SEO零流量,去tm的SEO,以后我也学小红书那样,把所有搜索引擎给屏蔽掉。 现在大家都在封锁自己的流量,不让你将流量引走,推特更是如此,发外链几乎零点击。现在各大社交平台,对引流管得最宽的唯有知乎了,可以给你随意发外链,而且对流量影响不大。 其他平台,如小红书、公众号,连外链都不能发,你只能发文本链接,公众号倒是可以填那个阅读原文,但谁会点? 不过即便是知乎,你发链接也仅仅只是为了引流罢了,知乎的外链有跳转页面,实测相当于屏蔽SEO。所以想要靠知乎发外链搞SEO的省省力吧,用处不大,而且外链本身就是引流的价值大于SEO,与其费时费力搞SEO,不如好好运营社媒。而在知乎上疯狂发外链引流,也不是高枕无忧的。偶尔在某些问题下回答,会引来某些无聊的人的恶意举报,一举报一个准,申诉都没用。 像那种“有什么有趣的网站推荐”、“有什么有深度的网站”,看似绝佳的网站宣传的问 ...

学习应该先追求深度还是广度?

知乎提问:学习应该先追求深度还是广度?我的回答:在我看来应该先追求广度,有了一定的广度再开始追求深度。因为选择深入哪个领域进行学习,是先需要广泛涉猎,对各个领域先有个初步的理解,接着再在这些领域中挑选一个进行深度学习。我当初学数学的时候,也是先大量的看各个数学分支的教材,广泛涉猎。然后挑选其中几个感兴趣的领域:微分几何和代数几何,开始着重学习。最后有了一定的数学成熟度,才开始全力追求深度,决定不仅是做代数几何,而且是代数几何中的算术几何。因此,比起一上来就追求深度,我认为先追求广度更加有效。因为任何一个领域都有成熟度这个概念,你没有一定的成熟度,过早的追求深度看似少走了很多弯路,但不过是拔苗助长。

Linus Kramer之拓扑群notes:Locally Compact Groups and Lie Groups

本notes顾名思义是关于局部紧致群和李群的,开篇先从最基本的拓扑群开始讲起,我当初就是靠这些内容补充拓扑群相关的基础的。为啥没有进一步往下学这个notes,一来是我不需要,二来是这个notes是残缺的,只写到第二章就没有了😅,即只有下图中画圈的部分。目前这本notes在网上已经绝迹,我今天倒是找到另一份残缺版,不过标题改成了Locally Compact Groups,内容倒是比之前的残缺版多一些。既然是属于稀缺资源,因此本notes除了学习价值以外,还有一定的收藏价值,因此我在此将该notes的两个版本都分享给有需要的人。PS:作者不再提供附件下载。

Charles Rezk拓扑学notes:Compactly Generated Spaces

本notes主要讲的是拓扑学中$k$-spaces与$k$-Hausdorff space的相关概念,之所以保存这份notes是因为我当初学习高阶范畴的时候,刚好需要用到这些概念。比如说,无穷范畴的定义就需要用到他们:A topological category is a category which is enriched over $\mathcal{C}\mathcal{G}$, the category of compactly generated (and weakly Hausdorff) topological spaces. The category of topological categories will be denoted by $\mathcal{C}at_{top}$.而抛开它与无穷范畴的联系,仅仅考虑它在拓扑学本身的意义,我觉得这也是本拓扑学方面有趣的notes,不仅是因为有趣的概念如$k$-空间、$k$-豪斯多夫空间,还有紧致生成的空间,还包括一些有趣的结论。总之,对高阶范畴、或者更深入的拓扑学感兴趣的人,可以看看。PS:作者不再提供附件下载。

陈省身微分几何经典教材《微分几何讲义》

一说到陈省身经典的微分几何教材《微分几何讲义》,就勾起我很多回忆。这本书是我初三时期入门微分几何的教材,虽然相比于Loring W Tu微分几何经典入门教材:An Introduction to Manifolds的教材没那么好理解,但是却比王幼宁的《微分几何讲义》更加的友好。我当时真的挺喜欢陈省身的教材的,虽然以我如今的水平看,当时的我并没有真正的看懂这本书,但这是我微分几何的启蒙书。我人生中看的第一本微分几何的书是王幼宁的《微分几何讲义》,但是我虽然很有兴趣,但却没能读下去,因为开篇就直接看不懂。而陈省身的《微分几何讲义》至少我能读下去,不至于开篇就直接来那么难的东西,我也是靠这本教材知道了很多微分几何的重要概念。我到高一还在看陈省身这本教材,直到后来高二为了读懂Jürgen Jost黎曼几何与几何分析教材:Riemannian Geometry and Geometric Analysis,我不得不看自己当时嫌弃的Loring W Tu的An Introduction to Manifolds,才打开了新世界,原来还是这么好看的微分几何入门教材,Loring W Tu的书确实比陈 ...

初中生如何自学数学?

知乎提问:我想这样子自学数学?纯兴趣爱好。我想从高中数学开始自学,用教材帮这本教辅书自学。然后学完高中后整理一下初等数学的知识。是不是就可以开始自学高数了?现在我打开高数好多证明题和不等式都不会做。然后把高等数学,数学分析,线性代数,高等代数,概率论与数理统计,复变函数与积分变换,实分析,复分析,泛函分析,抽象代数,代数几何,长微分方程,偏微分方程,微分几何都学完。大致就是这样的人生规划,初等数学学透了是不是就可以理解学习高等数学了?我的回答:我觉得按部就班的按顺序学习没多大意思,我初三的时候是先把导数、积分这些高中最难但却是微积分最基本的概念“学懂”,然后才学别的比较基础的概念如集合。原因无它,就是因为当时这些更感兴趣。因此与其纠结于把什么学透了再来理解什么,不如换成先尝试理解什么,理解不了再来理解什么。我初三的时候除了学会了导数、积分、加速度这些高中数学、物理的概念,但也没太过深入。顶多再学了个正余弦定理拿来应付中考。我从初中开始养成的习惯就是,对什么感兴趣就直接学它,学不懂再看其他的,因此我初中的时候还直接学了范畴的定义(只是看懂了表面的定义)。直到初三升高一的假期,我才买了高中 ...

点集拓扑求救

以及有没有推荐的点集拓扑教材