点击下方标题,迅速定位到你感兴趣的内容

  • 前言
  • 相关知识
  • 文本规范化
  • 英文Text-to-Phoneme
  • 中文Text-to-Phoneme

前言

Github:NLP相关Paper笔记和代码复现
说明:讲解时会对相关文章资料进行思想、结构、优缺点,内容进行提炼和记录,相关引用会标明出处,引用之处如有侵权,烦请告知删除。
转载请注明:DengBoCong

NLP的语音合成中,有一种关键技术是将文字拆解成音素,再去语音库里匹配相同音素的语音片段,来实现文字转换语音。音素是给定语言的语音,如果与另一个音素交换,则会改变单词的含义,同时,音素是绝对的,并不是特定于任何语言,但只能参考特定语言讨论音素。由于音素的特性,非常适合用于语音合成领域。

音素(phone),是语音中的最小的单位,依据音节里的发音动作来分析,一个动作构成一个音素。音素分为元音、辅音两大类。

说白了,音素其实就是人在说话时,能发出最最最最短小、简洁的不能再分割的发音,不同的音素就是不同的短发音,可以组成不同的长发音,再组成词句形成语言。

本篇文章就来讲讲中文和英文中,如何将文本转换为音素序列。

相关知识

众所周知,语音合成系统通常包含前端和后端两个模块。前端模块主要是对输入文本进行分析,提取后端模块所需要的语言学信息。前端模块一般包含文本正则化、分词、词性预测、多音字消歧、韵律预测等子模块。后端模块根据前端分析结果,通过一定的方法生成语音波形。后端模块一般分为基于统计参数建模的语音合成(Statistical Parameter Speech Synthesis,SPSS,以下简称参数合成),以及基于单元挑选和波形拼接的语音合成(以下简称拼接合成)两条技术主线。

而“端到端”架构的语音合成系统的出现,能够直接从字符文本合成语音,打破了各个传统组件之间的壁垒,使得我们可以从<文本,声谱>配对的数据集上,完全随机从头开始训练。最具代表性的端到端语音合成系统,就是2017年初,Google 提出的端到端的语音合成系统——Tacotron

从通俗一点的角度来讲,语音合成过程,需要处理两部分内容,分别是文本(Text)处理和音频(speech)处理,如下图是端到端的语音合成系统整体技术架构选型。我们文章要讲的就是属于TTS Frontend范畴的Text-to-Phoneme。

文本规范化

对文本进行预处理,主要是去掉无用字符,全半角字符转化等,对于中文而言,有时候普通话文本中会出现简略词、日期、公式、号码等文本信息,这就需要通过文本规范化,对这些文本块进行处理以正确发音,比如:

  • “小明体重是 128 斤”中的“128”应该规范为“一百二十八”,而“G128 次列车”中的“128” 应该规范为“一 二 八”
  • “2016-05-15”、“2016 年 5 月 15 号”、“2016/05/15”可以统一为一致的发音

对于英文而言,也需要将年份、货币、数字、字母等文本信息,转换为完整单词,比如:

  • 类别为年份(NYER): 2011 → twenty eleven
  • 类别为货币(MONEY): £100 → one hundred pounds
  • 类别为非单词,需要拟音(ASWD): IKEA → apply letter-to-sound
  • 类别为数字(NUM) : 100 NUM → one hundred
  • 类别为字母(LSEQ) : DVD → dee vee dee

这些文本规范化预处理不放在深度学习模型去学习,而是通过各种规则的正则表达式进行转换,所以涉及到的代码工作量还是比较大的,所以我将写好的代码更新至GitHub项目中,方便需要者使用(TensorFlow和PyTorch版本同步更新):NLP相关Paper笔记和代码复现,这里粘贴一个作为举例,方便大家知道是啥。

def _clean_number(text: str):"""对句子中的数字相关进行统一单词转换:param text: 单个句子文本:return: 转换后的句子文本"""comma_number_re = re.compile(r"([0-9][0-9\,]+[0-9])")decimal_number_re = re.compile(r"([0-9]+\.[0-9]+)")pounds_re = re.compile(r"£([0-9\,]*[0-9]+)")dollars_re = re.compile(r"\$([0-9\.\,]*[0-9]+)")ordinal_re = re.compile(r"[0-9]+(st|nd|rd|th)")number_re = re.compile(r"[0-9]+")text = re.sub(comma_number_re, lambda m: m.group(1).replace(',', ''), text)text = re.sub(pounds_re, r"\1 pounds", text)text = re.sub(dollars_re, _dollars_to_word, text)text = re.sub(decimal_number_re, lambda m: m.group(1).replace('.', ' point '), text)text = re.sub(ordinal_re, lambda m: inflect.engine().number_to_words(m.group(0)), text)text = re.sub(number_re, _number_to_word, text)return text

英文Text-to-Phoneme

我们先来讲讲英文的Text-to-Phoneme,想要将英文单词转换成音素,想必需要了解Arpabet,下面是WiKi上的解释:

ARPABET(也称为ARPAbet)是高级研究计划局(ARPA)在1970年代语音理解研究项目中开发的一组语音转录代码。 它代表具有不同ASCII字符序列的通用美国英语的音素和同音素。

可以理解为通过字母组合定义发音规则,英文发音是由元音辅音等组成的,同时,在元音后紧接着用数字表示压力, 辅助符号在1和2个字母的代码中相同, 在2个字母的符号中,段之间用空格隔开,大概如下这样:

我们将文本转换为ARPABET并不需要我们了解很多语言学的东西,我们只需要选择现有合适的发音字典就可以了,使用比较多的还是CMU的发音词典,官方网站,想了解原理的可以看这篇论文。可以先在官网体验一下是啥效果,如下:

自行从官网下载发音字典(也可以去我的github下载,链接在文章顶部),音素集,39个音素,如下:

     Phoneme Example Translation------- ------- -----------AA    odd     AA DAE  at  AE TAH  hut HH AH TAO   ought   AO TAW  cow K AWAY  hide    HH AY DB    be  B IYCH  cheese  CH IY ZD    dee D IYDH  thee    DH IYEH Ed  EH DER  hurt    HH ER TEY   ate EY TF   fee F IYG   green   G R IY NHH  he  HH IYIH it  IH TIY  eat IY TJH  gee JH IYK  key K IYL   lee L IYM   me  M IYN   knee    N IYNG  ping    P IH NGOW   oat OW TOY  toy T OYP   pee P IYR   read    R IY DS     sea S IYSH  she SH IYT  tea T IYTH  theta   TH EY T AHUH    hood    HH UH DUW   two T UWV   vee V IYW   we  W IYY   yield   Y IY L DZ   zee Z IYZH  seizure S IY ZH ER

有了音素集之后就可以使用脚本将文本转换为音素了,我的转换脚本如下:(完整代码同GitHub可找到)

def text_to_phonemes_converter(text: str, cmu_dict_path: str):"""将句子按照CMU音素字典进行分词切分:param text: 单个句子文本:param cmu_dict_path: cmu音素字典路径:return: 按照音素分词好的数组"""_, symbols_set = get_phoneme_dict_symbols()alt_re = re.compile(r'\([0-9]+\)')cmu_dict = {}text = _clean_text(text)text = re.sub(r"([?.!,])", r" \1", text)# 文件是从官网下载的,所以文件编码格式要用latin-1with open(cmu_dict_path, 'r', encoding='latin-1') as cmu_file:for line in cmu_file:if len(line) and (line[0] >= "A" and line[0] <= "Z" or line[0] == "'"):parts = line.split('  ')word = re.sub(alt_re, '', parts[0])# 这里要将非cmu音素的干扰排除pronunciation = " "temps = parts[1].strip().split(' ')for temp in temps:if temp not in symbols_set:pronunciation = Nonebreakif pronunciation:pronunciation = ' '.join(temps)if word in cmu_dict:cmu_dict[word].append(pronunciation)else:cmu_dict[word] = [pronunciation]cmu_result = []for word in text.split(' '):# 因为同一个单词,它的发音音素可能不一样,所以存在多个# 音素分词,我这里就单纯的取第一个,后面再改进和优化cmu_word = cmu_dict.get(word.upper(), [word])[0]if cmu_word != word:cmu_result.append("{" + cmu_word + "}")else:cmu_result.append(cmu_word)return " ".join(cmu_result)

中文Text-to-Phoneme

对于中文,其实我们再熟悉不过了,中文的音素其实就是汉语拼音的最小单元,包括声母,韵母,但是其中还会有一些整体认读音节,更详细的拼音标注文本分析,可以参考MTTS文本分析。同一个字在不同分词情况下的发音不同,所以导致数量级比较大,比较典型的可以参见清华大学的thchs30中文数据集,里面提供了分词好的音素字典,如下:

SIL sil
<SPOKEN_NOISE> sil
啊 aa a1
啊 aa a2
啊 aa a4
啊 aa a5
啊啊啊 aa a2 aa a2 aa a2
啊啊啊 aa a5 aa a5 aa a5
阿 aa a1
阿 ee e1
阿尔 aa a1 ee er3
阿根廷 aa a1 g en1 t ing2
阿九 aa a1 j iu3
阿克 aa a1 k e4
阿拉伯数字 aa a1 l a1 b o2 sh u4 z iy4
阿拉法特 aa a1 l a1 f a3 t e4

对应脚本在这里,不过其实汉子转拼音还有更方便的方式,就是使用Python 的拼音库 PyPinyin,如下:

from pypinyin import pinyin
print(pinyin('朝阳'))
# [['zhāo'], ['yáng']]

PyPinyin可以用于汉字注音、排序、检索等等场合,是基于 hotto/pinyin 这个库开发的,一些站点链接如下:

  • GitHub
  • 文档
  • PyPi

利器:TTS Frontend 中英Text-to-Phoneme Converter,附代码相关推荐

  1. ASP.NET的MVC中使用Cookie做身份验证(附代码下载)

    场景 ASP.NET的MVC中使用Session做身份验证(附代码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1071 ...

  2. ROI Align 在 R-FCN 中的推广:PSROI-Align(附代码)

    ROI Align 在 R-FCN 中的推广:PSROI-Align(附代码) 1. Position Sensitive ROI-Pooling 简介 原文:https://blog.csdn.ne ...

  3. python中get函数是什么意思_详解python中get函数的用法(附代码)_后端开发

    strncmp函数用法详解_后端开发 strncmp函数为字符串比较函数,其函数语法为"int strncmp ( const char * str1, const char * str2, ...

  4. python中soup_python中BeautifulSoup的详细介绍(附代码)

    本篇文章给大家带来的内容是关于python中BeautifulSoup的详细介绍(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. Beautiful Soup提供一些简单的. ...

  5. python数据格式简介_Python中数据类型时间的介绍(附代码)

    本篇文章给大家带来的内容是关于Python中数据类型时间的介绍(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 1.什么是时间数据类型 Python中表示时间类型的数据结构为 ...

  6. php 取字符串中的字母数字,php如何提取字符串中的数字?php提取字符串中数字的方法总结(附代码)...

    本篇文章给大家带来的内容是关于php如何提取字符串中的数字?php提取字符串中数字的方法总结(附代码) ,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. PHP提取字符串中的第一组数字 ...

  7. 北师大计算机组成原理答案,计算机组成原理(白中英)本科生试题库整理附答案[共21页].doc...

    PAGE 1 B)计算机. D 串行 A). -(2 -1) 7 当前的 CPU由(B )组成. A 控制器 D 控制器. ALU.主存 8 流水 CPU是由一系列叫做"段"的处理 ...

  8. Winform中实现文件批量更名器(附代码下载)

    场景 对一个文件夹中的文件进行某种格式的重命名 比如下面文件夹内的文件 程序运行效果 点击文件-打开,打开此文件夹后然后Ctrl+a全选此文件夹所有文件,点击打开 然后在序号设置中可以选择预设模板和起 ...

  9. Winform中实现自定义屏保效果(附代码下载)

    场景 效果 注: 博客主页: https://blog.csdn.net/badao_liumang_qizhi 关注公众号 霸道的程序猿 获取编程相关电子书.教程推送与免费下载. 实现 新建form ...

最新文章

  1. Ruby如何使用require从外部加载自定义类或模块
  2. 6.exit _exit _Exit
  3. 【抓包工具】HttpWatch(功能详细介绍)
  4. android actviity模糊,Framework启动过程浅析
  5. SSH框架配置及Maven使用
  6. sqlserver 遇到以零作除数错误的处理 不报错的解决方法
  7. programming review (c++): (1)vector, linked list, stack, queue, map, string, bit manipulation
  8. JQuery:视频+实战总结
  9. hdu1133-----递推+大数
  10. 泊松回归模型matlab,matlab拟合泊松分布
  11. 人人网相册加密密码破解
  12. 仿 Drools 决策表 Groovy 实现
  13. Workflow(12) DNSResolver
  14. css3 匀速运动的圆
  15. minui点击分页控件后滚动条置顶
  16. 阿拉丁年会 - 小程序开发者年度盛会 报告内容摘要
  17. 【总结】1111- 如何搞定Banner背景自动换色的功能?
  18. 加速网站访问的一些实践体会
  19. vue 强制刷新子组件
  20. 当北京爷们遭遇上海男人

热门文章

  1. easyexcel导出excel自定义合并单元格【动态表头和动态数据均可以自由合并】
  2. 梯度消失和梯度爆炸_梯度消失、爆炸的原因及解决办法
  3. QQ同时在线人数地图发布 沿海“大亮”
  4. Twelve South 为iPhone6和iPhone6 Plus发布了新的bookbook wallet 手机套
  5. 无人驾驶迎来新高度!以后每辆车都有这些功能...
  6. h5游戏:适应不同尺寸屏幕的WEB2048
  7. tomcat闪退错误排查
  8. Java:执行shell命令
  9. 预处理指令define和undef
  10. 【lazada运营】lazada怎么发货的?