[深度学习 - TTS自学之路] 基于fastspeech2 学习TTS流程以及部分代码梳理

2023-11-21 09:31

本文主要是介绍[深度学习 - TTS自学之路] 基于fastspeech2 学习TTS流程以及部分代码梳理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

深度学习方案 - TTS流程以及代码梳理 - fastspeech2

参考源码:https://github.com/ming024/FastSpeech2

最近好长一阵子没有写文章了,一方面是公司里做的一些项目不好公开写成文章,另一方面由于教育双减政策的影响,很多项目临时被停止了,所以这阵子,对原项目的维护以及新领域(音频)方面的自研学习,基本都在忙着,个人时间很少。
另外打个小广告,科室这边也逐渐对外写一些技术文章,主要在微信公众号:“ AI炼丹术 ”上发布。目前发布了很多关于端侧优化部署的文章、OCR相关技术文章等。后续我可能也会参与一些文章的写作发布。(可能关于人体相关技术或正在自我学习的音频方向)有兴趣的小伙伴可以关注一下,如果有帮助的话可以说是咸鱼推荐来的。。😏

本文的内容属于音频领域中TTS(text to speech),个人正在摸索,具体细节上的理解可能会有误,见谅。
另外还有一个关于音频的资料总结(来自一个知乎大佬:李永强):http://yqli.tech/page/tts_paper.html

一、步骤:

1. 前端处理

  • 输入文本 text,例如:text = 大家好!
  • 文本转拼音,例如:pinyins = ['da4', 'jia1', 'hao3']
from pypinyin import pinyin, Stylepinyins = [p[0]for p in pinyin(text, style=Style.TONE3, strict=False, neutral_tone_with_five=True)]
  • 拼音转韵律,例如:phones = ['d', 'a4', 'j', 'ia1', 'h', 'ao3']->'phones = {d a4 j ia1 h ao3}'
for p in pinyins: # lexicon 韵律表字典if p in lexicon:phones += lexicon[p]else:phones.append("sp") # 停顿
  • 韵律map成id,例如:sequence = [151, 174, 155, 226, 154, 193]
def text_to_sequence(text, cleaner_names):"""Converts a string of text to a sequence of IDs corresponding to the symbols in the text.The text can optionally have ARPAbet sequences enclosed in curly braces embeddedin it. For example, "Turn left on {HH AW1 S S T AH0 N} Street."Args:text: string to convert to a sequencecleaner_names: names of the cleaner functions to run the text throughReturns:List of integers corresponding to the symbols in the text"""sequence = []# Check for curly braces and treat their contents as ARPAbet:while len(text):m = _curly_re.match(text)if not m:sequence += _symbols_to_sequence(_clean_text(text, cleaner_names))breaksequence += _symbols_to_sequence(_clean_text(m.group(1), cleaner_names))sequence += _arpabet_to_sequence(m.group(2))text = m.group(3)return sequence

2. 声学模型 Fastspeech 2

  • 模型主要由三部分组成,encoder、adaptor、decoder;
  • encoder:韵律转换成数字信号后作为模型输入;
output = self.encoder(texts, src_masks)
  • VarianceAdaptor:输入音色 speaker、音高 pitch、音量 energy、语速 duration以及encoder部分的output; # speaker 这个源码里面加入multi-speaker TTS,即可以切换多个人的声音进行输出。

多人数据训练,通过参数speaker的调节音色。Alshell3 数据集由多个人的音色。

{"SSB1781": 0, "SSB1274": 1, "SSB1585": 2, "SSB1055": 3, "SSB1020": 4, "SSB0668": 5, "SSB1625": 6, ...} # speaker.json文件

p_control, e_control, d_control 作为音高、音量、语速的参数输入,输出合成的梅尔频谱(频谱包含时长信息)。

个人猜测这一块的作用决定了音频最终的音色、音高、音量、语速。可以通过这块调节,不同音量、语速或者个性化声音。

if self.speaker_emb is not None: # output = output + self.speaker_emb(speakers).unsqueeze(1).expand(-1, max_src_len, -1) # 将speaker加入encoder的output作为variance_adaptor部分的输入(output, p_predictions, e_predictions, log_d_predictions, d_rounded, mel_lens, mel_masks) = self.variance_adaptor(output, src_masks, mel_masks,
max_mel_len, p_targets, e_targets, d_targets, p_control, e_control, d_control)
  • decoder:将variance_adaptor的输出进行解码,生成梅尔频谱(维度一般为 T*80)或声波(维度一般为T * hop_size)。

fastspeech2 最终输出mel-spectrogram 梅尔频谱,梅尔频谱并不能直接生成音频,它需要再重构才能生成声波,进而生成音频,所以生成的梅尔频谱还需要经过声码器 vocoder,才能得到waveform。(mel-gan 、hifi-gan…);

而fastspeech2S 将声码器一起端到端训练,最终直接输出声波/音频。(2s找不到开源源码)

声波维度T * hop_size:这实际是一个上采样的过程,上采样的倍数为hop size*,*即一帧梅尔频谱特征要还原生成hop size个采样点; 如果音频采样率为22050,hop size设为256,则上采样的倍数为256。

output, mel_masks = self.decoder(output, mel_masks)
output = self.mel_linear(output) 
postnet_output = self.postnet(output) + output # 这个应该就是输出的梅尔频谱,原论文没有postnet,这层结构是源码作者自己加上的return (output, postnet_output, p_predictions, e_predictions,log_d_predictions, d_rounded, src_masks, mel_masks, src_lens, mel_lens,)

3. 声码器 vocoder - mel2wav

  • 声码器的作用:决定了合成音频的音质高低。
  • 个人猜测声码器可以解决合成的音频有噪声/人声不干净、人声不自然等情况,即训练作用:起润色音频(去噪、声调),而音频的音色、音高、音量、音速主要还是取决于声学模型。
  • 源码中提供了两种声码器, MelGAN 、 HiFi-GAN vocoder,我这边尝试的是hifi-gan。
  • 这个TTS源码中没有声码器训练的部分代码,higi-gan原始仓库:https://github.com/ranchlai/hifi-gan;

声码器的输入:梅尔频谱 - 一般为 T*80 ; 如 T为频谱长度,与音频长短相关。

声码器的输出:声波 - 一般为 T * hopsize (T在频谱上有)。waveform 长度:lengths = T * preprocess_config [“preprocessing”] [“stft”] [“hop_length”]

sampling_rate = preprocess_config["preprocessing"]["audio"]["sampling_rate"] # 加载配置-采样率
wavfile.write(os.path.join(path, "{}.wav".format(basename)), sampling_rate, wav) # 保存音频 (, lengths)

这篇关于[深度学习 - TTS自学之路] 基于fastspeech2 学习TTS流程以及部分代码梳理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/401445

相关文章

Java调用Python代码的几种方法小结

《Java调用Python代码的几种方法小结》Python语言有丰富的系统管理、数据处理、统计类软件包,因此从java应用中调用Python代码的需求很常见、实用,本文介绍几种方法从java调用Pyt... 目录引言Java core使用ProcessBuilder使用Java脚本引擎总结引言python

Java中ArrayList的8种浅拷贝方式示例代码

《Java中ArrayList的8种浅拷贝方式示例代码》:本文主要介绍Java中ArrayList的8种浅拷贝方式的相关资料,讲解了Java中ArrayList的浅拷贝概念,并详细分享了八种实现浅... 目录引言什么是浅拷贝?ArrayList 浅拷贝的重要性方法一:使用构造函数方法二:使用 addAll(

JAVA利用顺序表实现“杨辉三角”的思路及代码示例

《JAVA利用顺序表实现“杨辉三角”的思路及代码示例》杨辉三角形是中国古代数学的杰出研究成果之一,是我国北宋数学家贾宪于1050年首先发现并使用的,:本文主要介绍JAVA利用顺序表实现杨辉三角的思... 目录一:“杨辉三角”题目链接二:题解代码:三:题解思路:总结一:“杨辉三角”题目链接题目链接:点击这里

Node.js 中 http 模块的深度剖析与实战应用小结

《Node.js中http模块的深度剖析与实战应用小结》本文详细介绍了Node.js中的http模块,从创建HTTP服务器、处理请求与响应,到获取请求参数,每个环节都通过代码示例进行解析,旨在帮... 目录Node.js 中 http 模块的深度剖析与实战应用一、引言二、创建 HTTP 服务器:基石搭建(一

SpringBoot使用注解集成Redis缓存的示例代码

《SpringBoot使用注解集成Redis缓存的示例代码》:本文主要介绍在SpringBoot中使用注解集成Redis缓存的步骤,包括添加依赖、创建相关配置类、需要缓存数据的类(Tes... 目录一、创建 Caching 配置类二、创建需要缓存数据的类三、测试方法Spring Boot 熟悉后,集成一个外

SpringBoot使用minio进行文件管理的流程步骤

《SpringBoot使用minio进行文件管理的流程步骤》MinIO是一个高性能的对象存储系统,兼容AmazonS3API,该软件设计用于处理非结构化数据,如图片、视频、日志文件以及备份数据等,本文... 目录一、拉取minio镜像二、创建配置文件和上传文件的目录三、启动容器四、浏览器登录 minio五、

轻松掌握python的dataclass让你的代码更简洁优雅

《轻松掌握python的dataclass让你的代码更简洁优雅》本文总结了几个我在使用Python的dataclass时常用的技巧,dataclass装饰器可以帮助我们简化数据类的定义过程,包括设置默... 目录1. 传统的类定义方式2. dataclass装饰器定义类2.1. 默认值2.2. 隐藏敏感信息

opencv实现像素统计的示例代码

《opencv实现像素统计的示例代码》本文介绍了OpenCV中统计图像像素信息的常用方法和函数,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 统计像素值的基本信息2. 统计像素值的直方图3. 统计像素值的总和4. 统计非零像素的数量

IDEA常用插件之代码扫描SonarLint详解

《IDEA常用插件之代码扫描SonarLint详解》SonarLint是一款用于代码扫描的插件,可以帮助查找隐藏的bug,下载并安装插件后,右键点击项目并选择“Analyze”、“Analyzewit... 目录SonajavascriptrLint 查找隐藏的bug下载安装插件扫描代码查看结果总结Sona

Nginx、Tomcat等项目部署问题以及解决流程

《Nginx、Tomcat等项目部署问题以及解决流程》本文总结了项目部署中常见的four类问题及其解决方法:Nginx未按预期显示结果、端口未开启、日志分析的重要性以及开发环境与生产环境运行结果不一致... 目录前言1. Nginx部署后未按预期显示结果1.1 查看Nginx的启动情况1.2 解决启动失败的