语音合成之十三 中文文本归一化在现代语音合成系统中的应用与实践
中文文本归一化在现代语音合成系统中的应用与实践
- 引言
- 理解中文文本归一化(TN)
- 3 主流LLM驱动的TTS系统及其对中文文本归一化的需求分析
- A. SparkTTS(基于Qwen2.5)与文本归一化
- B. CosyVoice(基于Qwen)与文本归一化
- 4. Python库与代码实例
- A. 基础与通用库
- B. 综合性中文文本归一化工具包
- C. 专用转换库
- D. 综合归一化流程概念示例
- 建议与未来展望
引言
语音合成(Text-to-Speech, TTS)技术,旨在将文本信息转化为自然流畅的人类语音,已成为人机交互、内容播报和辅助技术等领域的核心组成部分 。近年来,大型语言模型(LLM)的崛起为TTS领域带来了革命性的进步,使得合成语音在自然度、表现力和个性化方面达到了前所未有的高度 。然而,高质量的语音合成始于对输入文本的精确理解和规范化处理。
中文文本因其语言特性,如缺乏显式词边界、多音字、以及数字、日期、特殊符号等非标准词(Non-Standard Words, NSW)的复杂表述方式,对TTS系统的前端处理提出了严峻挑战 。文本归一化(Text Normalization, TN),作为TTS系统前端的关键环节,其任务是将书面文本转换为标准化的、可供后续声学模型直接处理的口语化文本形式 。
理解中文文本归一化(TN)
中文文本归一化是将原始文本中包含的非标准词语(NSW)转换为TTS系统能够直接处理和正确发音的标准书面语或口语化表达的过程 。这一过程对于提升合成语音的质量至关重要。
-
A. 中文文本归一化的核心作用与重要性
- 提升发音准确性:原始中文文本常含有数字、日期、缩写、特殊符号等,若不加处理直接送入TTS后端,极易产生发音错误或不自然的韵律。例如,数字“123”应读作“一百二十三”,而非“一二三”或逐字发音 。文本归一化通过将这些NSW转换为规范的汉字表达,确保TTS系统能准确发声。
- 增强语音自然度:日常书面语中存在的缩写、非正式表达以及特定格式(如网址、邮件地址)需要被转换为更符合口语习惯的形式,从而使合成语音听起来更自然、更像人类讲话 。
- 消除歧义,提高可理解性:某些NSW,如特定格式的数字串或未经解释的缩写,可能存在多种解读方式,导致听者困惑。文本归一化致力于消除这些歧义,生成清晰、单一的口语化表达 。例如,“2023/5/11”应明确转换为“二零二三年五月十一日”或“两千零二十三年五月十一日”,避免按符号逐字朗读 。
- 作为TTS前端处理的基石:文本归一化是TTS系统前端处理流程中的初始且关键的一步,其输出质量直接影响后续的词性标注、韵律预测、声学模型处理等环节 。一个鲁棒的TN模块为整个TTS流程的顺畅运行和高质量输出奠定了坚实基础。在一些系统中,如Nuance Vocalizer,TN相关的代码甚至占到核心应用代码的20%以上,这足以说明其复杂性和重要性 。
-
B. 中文文本归一化的主要挑战
中文文本归一化面临的挑战主要源于中文语言的特性和NSW的多样性:- NSW形式多样复杂:数字(整数、小数、分数、百分比)、日期与时间(多种格式)、货币金额、度量单位、电话号码、网址、邮箱地址、数学符号、以及各种中英文缩写等,其书面形式与口语表达差异巨大,难以用简单规则完全覆盖 。
- 上下文歧义性:同一NSW在不同上下文中可能有不同的读法。例如,数字串“110”在“110米”中读作“一百一十”,在报警电话场景中则读作“幺幺零” 。这种歧义的解决高度依赖上下文语境信息。
- 口语表达的地域差异与习惯:对于某些NSW,如数字“二”和“两”的使用,不同地区或语境下有不同的口语习惯。
新词新语的涌现:网络时代不断产生新的缩写、表达方式,TN系统需要具备一定的扩展性和适应性。
-
C. 中文文本归一化流程与关键处理对象
典型的中文文本归一化流程通常包含预处理、非标准词识别与转换、后处理三个主要阶段 。- 预处理(Pre-processing):
- 字符宽度转换:将全角字符(如IPHONE,123)转换为半角字符(IPHONE, 123),以统一字符编码表示 。
- Unicode标准化:使用如NFKC(Normalization Form Compatibility Composition)等形式对Unicode文本进行标准化,确保字符表示的一致性,例如合并组合字符、转换兼容字符 。
- 繁简转换:根据TTS系统目标音库的语言,将输入文本统一转换为简体中文或繁体中文 。
- 无效字符或噪音去除:移除文本中不影响语义的控制字符、特定表情符号或预定义的黑名单词汇(如口头禅“呃”)。
- 非标准词(NSW)识别与转换:这是TN的核心环节,针对不同类型的NSW应用特定的转换规则。
- 数字(Numbers):
- 基数词:如“465”转换为“四百六十五”,“6.42”转换为“六点四二” 。
- 分数:“1/5”转换为“五分之一” 。
- 百分比:“6.3%”转换为“百分之六点三” 。
- 数字序列:电话号码、邮政编码、房间号等,如“12306”转换为“幺二三零六” 。这需要区分是作为数值还是序列来读。
- 特殊处理:如“二”和“两”的区分,通常在百、千、万等单位前或特定语境下使用“两”。
- 日期(Dates):
- 多种格式(“2002/01/28”,“2002-01-28”,“2002.01.28”)统一转换为规范读法,如“二零零二年一月二十八日” 。
- 年份的读法,如“2002年”可读作“二零零二年”或“两千零二年”。
- 时间(Time):
- “12:00”转换为“十二点”,“5:02”转换为“五点零二分”,“5:35:36”转换为“五点三十五分三十六秒” 。
- 处理am/pm标记,如“8:00 a.m.”转换为“早上八点” 。
- 货币(Money):
- “¥13.5”转换为“十三点五元”,“$13.5”转换为“十三点五美元” 。需要识别货币符号并转换为对应货币单位。
- 度量单位(Measure):
- “25kg”转换为“二十五千克”,“38°C”转换为“三十八摄氏度”,“10km/h”转换为“每小时十公里” 。单位符号需要展开为完整的中文名称。
- 数学表达式(Math):
- “78:96”(比分)转换为“七十八比九十六”,“-2”转换为“负二”,“±2”转换为“正负二” 。
- 缩写与特殊词(Abbreviations & Whitelist):
- 英文缩写如“CEO”可能读作字母序列“C E O”或根据约定俗成的中文对应词(如果存在)。
- 特定组合如“O2O”可能转换为“O to O” 。
- 通过白名单机制处理特定机构名、品牌名或其他专有名词的固定读法。
- 儿化音处理(Erhua):根据需求移除或保留儿化音,如“这地儿”可转换为“这地” 。
- 预处理(Pre-processing):
- 后处理(Post-processing):
- 标点符号处理:移除不影响韵律的标点,或将特定标点转换为停顿标记。例如,句末标点(如“!”、“。”)通常保留以指导韵律,而某些中间标点可能被移除或替换 。
- OOV(Out-Of-Vocabulary)标记:对于无法识别或转换的字符(如罕见字、非目标语言字符),进行标记,如“我们안녕”转换为“我们안녕” 。
- 文本格式整理:去除转换过程中可能产生的多余空格等。
中文文本归一化的复杂性在于,它不仅仅是简单的字符串替换,而是需要结合语言学知识、上下文信息,有时甚至需要机器学习模型来解决歧义问题 。一个设计良好的TN系统能够显著提升TTS的最终效果。
3 主流LLM驱动的TTS系统及其对中文文本归一化的需求分析
基于LLM的TTS模型如SparkTTS和CosyVoice,凭借其强大的文本理解和生成能力,在语音合成领域取得了显著进展。然而,这些模型在处理原始中文文本时,对文本归一化的依赖程度和处理方式各有侧重。
A. SparkTTS(基于Qwen2.5)与文本归一化
SparkTTS是一个基于Qwen2.5 LLM的高效文本转语音模型 。它通过BiCodec将语音分解为语义标记和全局说话人属性标记,并利用Qwen2.5进行建模 。
尽管SparkTTS基于Qwen2.5,但其公开的资料(包括论文摘要和GitHub)并未详细说明其内置的中文文本归一化具体规则和覆盖范围 。虽然LLM可能隐式处理一些简单的NSW,但对于复杂的中文特有现象(如“幺”的读法、特定的日期和金额格式转换),其鲁棒性从测试结果来看并不理想,而归一化之后的文本则具有较好的处理效果。
因此对于SparkTTS,尽管其依赖的Qwen2.5 LLM具有强大的文本处理能力,但为了确保在各种复杂中文输入下的语音合成准确性和自然度,进行显式的中文文本归一化预处理仍然是推荐的做法。依赖LLM自身隐式处理所有NSW可能存在风险,特别是在对发音准确性要求极高的场景。一个外部的、规则明确的TN模块可以作为重要的保障。
B. CosyVoice(基于Qwen)与文本归一化
CosyVoice是另一个基于LLM(如Qwen)的先进TTS系统,支持多语言和零样本语音克隆,并特别强调了流式合成能力 。 SparkTTS仅开源了低采样率的模型和其推理代码,而CosyVoice的开源较为详细,涵盖了各种模型、数据集一集训练的代码,是推荐入手的模型。
“原始文本输入”与BPE分词器:CosyVoice 2的一个特点是直接使用“原始文本”作为输入,并通过一个基于BPE(Byte Pair Encoding)的分词器进行处理 。这种方式旨在简化数据预处理流程,使模型能够以端到端的方式学习词汇在不同上下文中的发音。
集成的文本归一化选项:CosyVoice在其GitHub仓库中明确提到了文本归一化处理。它提供了两种选项:
WeTextProcessing:默认使用的文本归一化工具,如果ttsfrd
未安装 。WeTextProcessing
是一个功能较全面的中文TN工具包 。
ttsfrd:一个可选的文本归一化包,据称可能提供更好的TN性能 。其规则基于Zhiyang Zhou的工作,涵盖了多种中文NSW类型 。
frontend.py
中的处理逻辑:CosyVoice
的frontend.py
代码(如中部分展示)清晰地显示了在文本送入模型前,会根据配置选择ttsfrd
或WeTextProcessing(通过self.zh_tn_model.normalize(text)
)对中文文本进行归一化处理。
结论:对于CosyVoice,中文文本归一化是其系统设计中明确考虑并集成的一环。用户可以选择使用其默认的WeTextProcessing
或配置性能可能更优的ttsfrd。这意味着CosyVoice认识到,即使采用了先进的LLM和端到端学习策略,一个专门的中文TN模块对于处理复杂中文输入、保证合成质量仍然是必要的。
4. Python库与代码实例
为了在Python环境中实现中文文本归一化,开发者可以利用一系列开源库。这些库功能各异,有的专注于基础的字符处理,有的提供全面的NSW规则,有的则针对特定类型的转换。
A. 基础与通用库
unicodedata
(Python标准库)
- 功能: 提供对Unicode字符数据库的访问,常用于字符属性检查和Unicode文本的标准化(如NFC, NFD, NFKC, NFKD形式的转换)。对于中文TN,NFKC范式特别有用,它可以将全角字符转换为半角,并处理一些兼容字符,有助于文本的初步清理和统一。
- 安装: Python内置,无需额外安装。
- 用途: 文本预处理阶段,进行字符层面的规范化,特别是全角到半角的转换。
代码示例:
Pythonimport unicodedatatext_full_width = "IPHONE手机,价格:1234元,ABC"
# 使用NFKC进行归一化,全角数字和字母会转为半角
normalized_text_nfkc = unicodedata.normalize('NFKC', text_full_width)print(f"原始文本: {text_full_width}")
print(f"NFKC 归一化后: {normalized_text_nfkc}")
# 预期输出: IPHONE手机,价格:1234元,ABC
相关集成: 阿里云LLM文本标准化组件使用ftfy.fix_text(text, normalization=‘NFKC’),其核心也依赖unicodedata的原理 。
-
OpenCC-Python
(或opencc-python-reimplemented
, OpenCC)- 功能: 提供高质量的中文简繁体转换,支持词汇级别转换、异体字转换以及中国大陆、台湾、香港等地区的用词习惯转换 。
- 安装: pip install opencc-python-reimplemented 或 pip install opencc 。后者是官方维护的更新版本。
- 用途: 根据TTS系统的目标音库(简体或繁体)统一输入文本的字符集。
代码示例 (使用 opencc):
import unicodedatatext_full_width = "IPHONE手机,价格:1234元,ABC"
# 使用NFKC进行归一化,全角数字和字母会转为半角
normalized_text_nfkc = unicodedata.normalize('NFKC', text_full_width)print(f"原始文本: {text_full_width}")
print(f"NFKC 归一化后: {normalized_text_nfkc}")
# 预期输出: IPHONE手机,价格:1234元,ABC
- 相关集成: 阿里云LLM文本标准化组件使用opencc包进行繁简转换 。
B. 综合性中文文本归一化工具包
- WeTextProcessing
- 功能: 一个面向生产环境的中文文本归一化(TN)与反归一化(ITN)工具包,提供了针对多种NSW的详细规则,并包含预处理和后处理流程 。
- 安装:
pip install WeTextProcessing
。通常需要通过conda安装其依赖pynini:conda install -c conda-forge pynini
。
中文TN主要特性: - 数字归一化:基数、分数、百分比。
- 日期和时间归一化。
- 货币和度量单位归一化。
- 数字序列(如电话号码)归一化。
- 儿化音去除选项。
- 字符宽度转换(全角到半角)。
- 标点符号处理规则。
- 通过白名单/黑名单进行自定义处理 。
from tn.chinese.normalizer import Normalizer as ZhNormalizer# 假设WeTextProcessing已正确安装,并且规则文件可访问
# 初始化中文归一化器,例如,选择去除儿化音
# 在实际使用中,cache_dir可能需要指向WeTextProcessing规则编译后的缓存路径
# overwrite_cache=True 会强制重新编译规则,首次运行时或规则更新后使用
try:zh_tn_model = ZhNormalizer(remove_erhua=True, overwrite_cache=False)
except Exception as e:print(f"初始化ZhNormalizer失败,请确保pynini和相关规则已正确配置: {e}")print("尝试不使用缓存 (可能较慢,且需要规则源文件):")# zh_tn_model = ZhNormalizer(remove_erhua=True, overwrite_cache=True, cache_dir=None) # 示例raise etext_to_normalize = "总量的1/5以上,价格是¥13.5,今天是2022/01/28,我儿子喜欢这地儿。电话是13800138000。"
normalized_text = zh_tn_model.normalize(text_to_normalize)print(f"原始文本: {text_to_normalize}")
print(f"WeTextProcessing 归一化后: {normalized_text}")
# 预期输出 [8]:
# 总量的五分之一以上,价格是十三点五元,今天是二零零二年一月二十八日,我儿子喜欢这地。电话是幺三八零零幺三八零零零。
- 相关集成: CosyVoice默认使用WeTextProcessing进行文本归一化 。
- NVIDIA NeMo-text-processing
-
功能: 基于加权有限状态转换器(WFST)的文本归一化和反归一化工具,支持包括中文(zh)在内的多种语言 。
-
安装:
pip install nemo_text_processing
或从源码安装。依赖pynini,推荐通过conda安装:conda install -c conda-forge pynini==2.1.5
(版本号可能需根据NeMo版本调整) 。 -
中文TN主要特性: 支持中文的TN和ITN 。WFST基础使其在模式匹配方面非常强大和高效。可以利用缓存的编译语法文件(.far)来加速处理 。
-
代码示例 (Python调用方式): NeMo的TN功能主要通过normalize.py脚本或其内部的Normalizer类来使用。以下是一个概念性的Python调用示例,具体API参数和用法请参考NeMo官方文档。
-
相关资料: NeMo提供了详细的WFST教程,解释了如何构建和使用语法 。中文的特定语法规则文件(.tsv或Python定义的规则)位于NeMo-text-processing/nemo_text_processing/text_normalization/zh/目录下,例如cardinal.py用于处理基数词 。
C. 专用转换库
num2chinese / ChineseNumberUtils
- 功能: 专注于阿拉伯数字与中文数字字符之间的相互转换 。ChineseNumberUtils支持简繁体、大写数字,并能处理较大的数值范围和“二/两”的用法。
- 安装:
pip install num2chinese
或pip install ChineseNumberUtils
。 - 用途: 在TN流程中专门处理数字字符串的转换,可以作为更大型TN系统的一个组件,或者在对数字格式有特殊要求时使用。
- 代码示例 :
from cnc import convert# 阿拉伯数字转中文
number1 = 578.5
chinese_numeral_s = convert.number2chinese(number1, language="S") # 简体
chinese_numeral_t_big = convert.number2chinese(number1, language="T", bigNumber=True) # 繁体大写print(f"数字: {number1}")
print(f"简体中文数字: {chinese_numeral_s}") # 预期: 五百七十八点五
print(f"繁体大写中文数字: {chinese_numeral_t_big}") # 预期: 伍佰柒拾捌點伍# 中文转阿拉伯数字
chinese_text1 = "两千零一十二"
arabic_number1 = convert.chinese2number(chinese_text1)
chinese_text2 = "贰佰零贰" # 大写简体
arabic_number2 = convert.chinese2number(chinese_text2)print(f"中文文本: {chinese_text1} => 阿拉伯数字: {arabic_number1}") # 预期: 2012
print(f"中文文本: {chinese_text2} => 阿拉伯数字: {arabic_number2}") # 预期: 202
ttsfrd
- 功能: 作为CosyVoice中的一个可选中文TN模块,据称能提供更好的性能 。其规则基于Zhiyang Zhou的工作,涵盖了基数词、日期、数字、分数、金额、百分比、电话等NSW的归一化 。
- 安装: 通常通过CosyVoice项目提供的.whl文件进行安装 。
- 用途: 主要集成在CosyVoice系统内部。其frontend.py中通过self.frd.do_voicegen_frd(text)调用 。独立使用的API细节在现有资料中尚不完全清晰,但其核心能力是针对中文NSW的规则化处理。
- 代码示例 (概念性,基于CosyVoice内部调用):
# 概念性代码,ttsfrd的直接API调用需查阅其具体实现或文档
# class TTSFRD_Handler:
# def __init__(self):
# # 此处进行ttsfrd相关初始化
# # self.frd = ttsfrd.Frontend() # 假设的初始化方式
# pass# def normalize_text(self, chinese_text: str) -> str:
# # normalized_data = self.frd.do_voicegen_frd(chinese_text) # 调用核心处理
# # sentences_data = json.loads(normalized_data)["sentences"]
# # return "".join([item["text"] for item in sentences_data])
# return "示例:ttsfrd处理后的文本" # 占位符# handler = TTSFRD_Handler()
# text = "价格12块5,日期86年8月18日"
# normalized = handler.normalize_text(text)
# print(f"ttsfrd 归一化后 (概念): {normalized}")
- whisper-normalizer
- 功能: 实现了OpenAI Whisper模型中使用的文本归一化算法,主要包含BasicTextNormalizer和EnglishTextNormalizer 。
- 对中文的适用性: 文档明确提示,“在母语中使用BasicTextNormalizer可能不是一个好主意”,并且指出其在印地语等资源较少的语言中可能存在问题 。这意味着直接将其用于中文TN可能效果不佳,除非针对中文进行大量的规则定制和适配。其主要设计目标是为ASR评估提供一致的文本处理,而非专门为中文TTS的口语化转换。
- 代码示例 (通用,非中文优化):
from whisper_normalizer.basic import BasicTextNormalizer# BasicTextNormalizer主要进行一些通用清理,如小写化、移除特定标点等
# 对中文的NSW处理能力有限
normalizer = BasicTextNormalizer()
text = "这是 一段CHINESE文本,包含123。"
normalized_text = normalizer(text)print(f"原始文本: {text}")
print(f"Whisper BasicTextNormalizer 后: {normalized_text}")
# 预期输出 (可能只是小写化和一些符号处理): 这是 一段chinese文本,包含123。
D. 综合归一化流程概念示例
在实际应用中,通常需要组合使用这些库来实现一个鲁棒的中文文本归一化流程。以下是一个概念性的Python函数,展示了如何将多个工具串联起来:
import unicodedata
import opencc # 假设使用官方 opencc 包
from tn.chinese.normalizer import Normalizer as WeTextProcessingNormalizer # 假设 WeTextProcessing 已安装且路径配置正确
from cnc import convert as num_converter # 假设 ChineseNumberUtils 已安装# 初始化转换器 (一次性)
oc_converter = None
try:oc_converter = opencc.OpenCC('t2s.json') # 示例:繁体到简体
except Exception as e:print(f"OpenCC 初始化失败: {e}")wetext_normalizer = None
try:# 实际使用时,请确保 pynini 及 WeTextProcessing 的规则文件路径正确# cache_dir 指向编译好的.far 文件目录,若为 None 或路径无效,可能尝试从源规则编译wetext_normalizer = WeTextProcessingNormalizer(remove_erhua=True, overwrite_cache=False)
except Exception as e:print(f"WeTextProcessing Normalizer 初始化失败: {e}")def comprehensive_chinese_tn_pipeline(text: str) -> str:print(f"原始输入: {text}")# 步骤 1: Unicode 归一化 (例如 NFKC)try:text = unicodedata.normalize('NFKC', text)print(f"Unicode NFKC 归一化后: {text}")except Exception as e:print(f"Unicode 归一化失败: {e}")# 根据策略决定是否继续或抛出异常# 步骤 2: 繁简转换 (按需选择,此处示例为繁转简)if oc_converter:try:text = oc_converter.convert(text)print(f"OpenCC 繁转简后: {text}")except Exception as e:print(f"OpenCC 转换失败: {e}")else:print("OpenCC 未初始化,跳过繁简转换。")# 步骤 3: 使用综合性工具包进行NSW归一化 (如 WeTextProcessing)if wetext_normalizer:try:text = wetext_normalizer.normalize(text)print(f"WeTextProcessing 归一化后: {text}")except Exception as e:print(f"WeTextProcessing 处理失败: {e}")else:print("WeTextProcessing Normalizer 未初始化,跳过NSW归一化。")# 步骤 4: (可选) 针对特定需求,使用专用库进行补充处理# 例如,如果WeTextProcessing对某种数字格式处理不符合预期,可以在此用 ChineseNumberUtils 等进行修正# 此处仅为示例,实际中需要判断是否必要# if "特定未处理模式" in text:# text = custom_specific_normalization(text, num_converter)# print(f"特定规则补充处理后: {text}")# 步骤 5: 最终清理 (例如,去除可能由多步处理引入的多余空格)text = " ".join(text.split())print(f"最终清理后: {text}")return text# 示例调用
raw_text_example = "臺北的氣溫是25°C,價格是NT$100元,佔總數的1/2。電話是02-27376666。"
if __name__ == '__main__':# 确保在主模块执行时进行初始化和调用,避免多进程问题# (上面初始化部分已移至全局,实际应用中需考虑初始化时机)if not oc_converter or not wetext_normalizer:print("错误:一个或多个核心归一化组件未能成功初始化。请检查依赖和配置。")else:normalized_for_tts = comprehensive_chinese_tn_pipeline(raw_text_example)print(f"\n最终送往TTS的文本: {normalized_for_tts}")# 预期输出 (概念性,实际输出依赖各库的具体实现和规则):# 台北的气温是25摄氏度,价格是新台币100元,占总数的二分之一。电话是零二二七三七六六六六。
这个流程展示了多层次处理的思想:从基础的字符层面标准化,到简繁统一,再到复杂的NSW处理,最后进行清理。实际应用中,每一步的选择和顺序可能需要根据具体需求和所用库的特性进行调整和优化。重要的是,没有一个单一的库能够完美解决所有中文TN问题,组合使用往往是必要的。
表1: 主要Python中文文本归一化库对比
库名称 | 主要功能 | 中文TN关键特性 | 安装方式 (pip) | 主要依赖 | 理想使用场景 |
---|---|---|---|---|---|
unicodedata | Unicode字符数据库访问与标准化 | 全角转半角 (NFKC),字符属性查询 | Python内置 | 无 | 文本预处理,字符层面一致性处理 |
opencc-python / OpenCC | 中文简繁体转换 | 支持简繁、地区词汇(大陆、台湾、香港)转换 | opencc 或 opencc-python-reimplemented | OpenCC核心库 (通常随包提供) | 统一输入文本的简繁体 |
WeTextProcessing | 中文TN与ITN | 数字、日期、时间、货币、度量衡、序列号归一化;儿化音处理;字符宽度转换;标点规则;白名单 | WeTextProcessing | pynini (通常需conda安装) | 作为TTS系统主要的中文TN引擎,处理各类NSW |
NVIDIA NeMo-text-processing | 多语言TN与ITN (基于WFST) | 支持中文TN/ITN;WFST规则驱动;可缓存语法 | nemo_text_processing | pynini (通常需conda安装), PyTorch(可选) | 需要高性能、基于WFST的TN方案,特别是在NVIDIA生态中 |
ChineseNumberUtils | 中文数字与阿拉伯数字互转 | 支持大数、小数、简繁体、大写数字、“二/两”区分 | ChineseNumberUtils | 无 | 专门处理数字与中文数字字符的转换,或作为大型TN系统的补充 |
ttsfrd | 中文TN (CosyVoice选用) | 基于规则的NSW处理(数字、日期、金额等) | 通过CosyVoice提供的.whl文件安装 | pynini (通过ttsfrd_dependency.whl) | 主要用于CosyVoice系统,或希望使用其特定规则集的场景 |
whisper-normalizer | OpenAI Whisper的文本归一化算法实现 | 基础文本清理,英文归一化。对中文NSW处理能力有限,不推荐直接用于复杂中文TN | whisper-normalizer | 无 | ASR评估时的文本标准化,不适合作为中文TTS的主要TN工具 |
这个表格为开发者选择合适的Python库提供了清晰的对比和参考。选择时应综合考虑项目需求、输入文本的复杂程度、对特定NSW处理的精细度要求以及系统环境的依赖。通常,一个稳健的中文TN方案会结合unicodedata进行预处理,OpenCC进行简繁转换,再选用WeTextProcessing或NeMo-text-processing作为主要的NSW处理引擎,并可能辅以ChineseNumberUtils等专用库处理特定细节。
建议与未来展望
为LLM驱动的TTS系统实现高效且准确的中文文本归一化,需要周全的策略和对可用工具的深入理解。同时,该领域仍在不断发展,展现出一些值得关注的趋势。中文文本归一化在LLM驱动的TTS中的最佳实践
- 坚持显式归一化优先:尽管LLM具备一定的语言理解能力,但不应完全依赖其隐式处理复杂的中文NSW。一个明确的、前置的TN流程能显著提升系统的鲁棒性、可预测性和最终语音的准确性。对于规则明确的转换(如特定数字读法、日期格式),显式规则通常比LLM的概率性生成更为可靠。
- 采用分层处理策略:构建一个多层次的TN流程。首先进行基础的Unicode标准化(如使用unicodedata进行NFKC转换)和必要的简繁转换(使用OpenCC)。随后,应用一个综合性的中文TN工具包(如WeTextProcessing或NVIDIA NeMo-text-processing)来处理常见的NSW。最后,可以针对特定领域或未覆盖的边缘情况,补充自定义规则或专用库(如ChineseNumberUtils)。
- 重视上下文消歧:中文NSW的歧义性是一大挑战(例如,“110”的读法)。对于这类情况,需要利用上下文信息。这可以通过设计更精细的规则(如在WFST中编码上下文约束)或训练专门的机器学习/LLM组件来辅助判断 。例如,Llama在TTS前端的研究中就包含了同形异义词消歧任务 。
- 进行严格和全面的测试:建立一个覆盖各类中文NSW(数字、日期、时间、金额、度量、地址、电话、缩写等)、不同格式、以及潜在歧义和边缘案例的测试集。不仅要评估TN模块的文本输出,更要结合TTS系统评估最终合成语音的准确性和自然度。
- 确保规则和模型的可维护性:如果TN流程中包含基于规则的组件(如WFST或正则表达式),务必确保这些规则有良好的文档、易于理解和修改。对于基于机器学习或LLM的TN组件,应建立完善的数据管理、模型训练和版本控制流程。
- 考虑用户自定义和白名单机制:对于特定行业应用或用户群体,可能存在独特的术语、缩写或读法偏好。提供白名单功能(如WeTextProcessing 和NeMo 所支持的)允许用户自定义归一化行为,能显著提升系统的适应性和用户满意度。
中文文本归一化技术,尤其是在LLM的背景下,正朝着更智能、更融合的方向发展:
- LLM与TN的更紧密融合:未来的TTS系统可能会看到LLM更深入地参与到TN过程中,不仅仅是接收已归一化的文本。LLM有望在理解上下文的基础上,更智能地指导NSW的读法选择,甚至参与到部分归一化任务中,如更复杂的歧义消解和风格化朗读(例如,将“100元”根据上下文读作“一百块”或“一百元”)。
- 端到端归一化的潜力与挑战:虽然完全依赖LLM进行端到端的隐式归一化(即从原始文本直接到声学特征,中间不经过明确的文本转换步骤)在理论上可行,并且LLM能从大规模(文本,语音)数据中学习一些常见模式,但对于低频、复杂或有严格发音规则的中文NSW,其鲁棒性和准确性仍是巨大挑战。确定性的规则在这些场景下仍具有不可替代的优势。
- 上下文感知能力的增强:LLM的上下文理解能力将持续赋能TN。例如,对于数字“一”在电话号码中读“幺”,在序数词中读“一”,LLM可以凭借其对篇章级上下文的把握,更准确地指导这些发音选择。
- 零样本/少样本适应性:借助LLM强大的泛化能力,未来TN系统有望在少量甚至无需特定领域样本的情况下,快速适应新领域、新词汇或特定用户群体的归一化需求。
- 中文TN基准的标准化与完善:目前,相较于英文(如Google Text Normalization dataset ),公开的、大规模、高质量的中文TN评测基准相对缺乏。未来有望出现更完善的中文TN数据集和评测标准,以推动该领域技术的发展和客观比较。
- 混合模型成为主流:纯规则系统在处理灵活性和上下文感知方面有局限,而纯LLM系统在确定性和细粒度控制方面可能不足。因此,结合规则(如WFST)的确定性、高效性与LLM的上下文理解、泛化能力的混合模型,很可能成为未来中文TN的主流解决方案。这种混合系统能够利用规则处理明确的、模式化的NSW,同时利用LLM处理更复杂、更依赖上下文的归一化任务和歧义消解。
相关文章:
语音合成之十三 中文文本归一化在现代语音合成系统中的应用与实践
中文文本归一化在现代语音合成系统中的应用与实践 引言理解中文文本归一化(TN)3 主流LLM驱动的TTS系统及其对中文文本归一化的需求分析A. SparkTTS(基于Qwen2.5)与文本归一化B. CosyVoice(基于Qwen)与文本归…...
9.1.领域驱动设计
目录 一、领域驱动设计核心哲学 战略设计与战术设计的分野 • 战略设计:限界上下文(Bounded Context)与上下文映射(Context Mapping) • 战术设计:实体、值对象、聚合根、领域服务的构建原则 统一语言&am…...
如何配置光猫+路由器实现外网IP访问内部网络?
文章目录 前言一、网络拓扑理解二、准备工作三、光猫配置3.1 光猫工作模式3.2 光猫端口转发配置(路由模式时) 四、路由器配置4.1 路由器WAN口配置4.2 端口转发配置4.3 动态DNS配置(可选) 五、防火墙设置六、测试配置七、安全注意事…...
C++题题题题题题题题题踢踢踢
后缀表达式求值 #include<bits/stdc.h> #include<algorithm> using namespace std; string a[100]; string b[100]; stack<string> op; int la0,lb0; int main(){while(true){cin>>a[la];if(a[la]".") break;la;}for(int i0;i<la;i){if(…...
M. Moving Both Hands(反向图+Dijkstra)
Problem - 1725M - Codeforces 题目大意:给你一个有向图,起始点在1,问起始点分别与另外n-1个 点相遇的最短时间,无法相遇输出-1。 思路:反向建图,第一层建原图,第二层建反向图,两层…...
11、参数化三维产品设计组件 - /设计与仿真组件/parametric-3d-product-design
76个工业组件库示例汇总 参数化三维产品设计组件 (注塑模具与公差分析) 概述 这是一个交互式的 Web 组件,旨在演示简单的三维零件(如带凸台的方块)的参数化设计过程,并结合注塑模具设计(如开模动画)与公…...
智能座舱开发工程师面试题
一、基础知识类 简述智能座舱的核心组成部分及其功能 要求从硬件(如显示屏、传感器、控制器)和软件(操作系统、中间件、应用程序)层面展开,阐述各部分如何协同实现座舱的智能化体验。 对比 Android Automotive、QNX…...
【连载14】基础智能体的进展与挑战综述-多智能体系统设计
基础智能体的进展与挑战综述 从类脑智能到具备可进化性、协作性和安全性的系统 【翻译团队】刘军(liujunbupt.edu.cn) 钱雨欣玥 冯梓哲 李正博 李冠谕 朱宇晗 张霄天 孙大壮 黄若溪 在基于大语言模型的多智能体系统(LLM-MAS)中,合作目标和合…...
06.three官方示例+编辑器+AI快速学习webgl_animation_skinning_additive_blending
本实例主要讲解内容 这个Three.js示例展示了**骨骼动画(Skinning)和变形动画(Morphing)**的结合应用。通过加载一个机器人模型,演示了如何同时控制角色的肢体动作和面部表情,实现更加丰富的角色动画效果。 核心技术包括: 多动画混合与淡入…...
【Java学习日记36】:javabeen学生系统
ideal快捷键...
.Net HttpClient 使用请求数据
HttpClient 使用请求数据 0、初始化及全局设置 //初始化:必须先执行一次 #!import ./ini.ipynb1、使用url 传参 参数放在Url里,形如:http://www.baidu.com?namezhangsan&age18, GET、Head请求用的比较多。优点是简单、方便࿰…...
详解 Java 并发编程 synchronized 关键字
synchronized 关键字的作用 synchronized 是 Java 中用于实现线程同步的关键字,主要用于解决多线程环境下的资源竞争问题。它可以修饰方法或代码块,确保同一时间只有一个线程可以执行被修饰的代码,从而避免数据不一致的问题。 synchronized…...
《Go小技巧易错点100例》第三十二篇
本期分享: 1.sync.Map的原理和使用方式 2.实现有序的Map sync.Map的原理和使用方式 sync.Map的底层结构是通过读写分离和无锁读设计实现高并发安全: 1)双存储结构: 包含原子化的 read(只读缓存,无锁快…...
时序约束高级进阶使用详解四:Set_False_Path
目录 一、背景 二、Set_False_Path 2.1 Set_false_path常用场景 2.2 Set_false_path的优势 2.3 Set_false_path设置项 2.4 细节区分 三、工程示例 3.1 工程代码 3.2 时序约束如下 3.3 时序报告 3.4 常规场景 3.4.1 设计代码 3.4.2 约束场景 3.4.3 约束对象总结…...
每日定投40刀BTC(16)20250428 - 20250511
定投 坚持 《恒道》 长河九曲本微流,岱岳摩云起累丘。 铁杵十年销作刃,寒窗五鼓淬成钩。已谙蜀栈盘空险,更蓄湘竹带泪遒。 莫问枯荣何日证,星霜满鬓亦从头。...
C# 高效处理海量数据:解决嵌套并行的性能陷阱
C# 高效处理海量数据:解决嵌套并行的性能陷阱 问题场景 假设我们需要在 10万条ID 和 1万个目录路径 中,快速找到所有满足以下条件的路径: 路径本身包含ID字符串该路径的子目录中也包含同名ID 初始代码采用Parallel.ForEach嵌套Task.Run&am…...
【Java EE初阶 --- 多线程(初阶)】线程安全问题
乐观学习,乐观生活,才能不断前进啊!!! 我的主页:optimistic_chen 我的专栏:c语言 ,Java 欢迎大家访问~ 创作不易,大佬们点赞鼓励下吧~ 文章目录 线程不安全的原因根本原因…...
从InfluxDB到StarRocks:Grab实现Spark监控平台10倍性能提升
Grab 是东南亚领先的超级应用,业务涵盖外卖配送、出行服务和数字金融,覆盖东南亚八个国家的 800 多个城市,每天为数百万用户提供一站式服务,包括点餐、购物、寄送包裹、打车、在线支付等。 为了优化 Spark 监控性能,Gr…...
《Redis应用实例》学习笔记,第一章:缓存文本数据
前言 最近在学习《Redis应用实例》,这本书并没有讲任何底层,而是聚焦实战用法,梳理了 32 种 Redis 的常见用法。我的笔记在 Github 上,用 Jupyter 记录,会有更好的阅读体验,作者的源码在这里:h…...
Redis 缓存
缓存介绍 Redis 最主要三个用途: 1)存储数据(内存数据库) 2)消息队列 3)缓存 对于硬件的访问速度,通常有以下情况: CPU 寄存器 > 内存 > 硬盘 > 网络 缓存的核心…...
Apache Flink 与 Flink CDC:概念、联系、区别及版本演进解析
Apache Flink 与 Flink CDC:概念、联系、区别及版本演进解析 在实时数据处理和流式计算领域,Apache Flink 已成为行业标杆。而 Flink CDC(Change Data Capture) 作为其生态中的重要组件,为数据库的实时变更捕获提供了强大的能力。 本文将从以下几个方面进行深入讲解: 什…...
缓存(4):常见缓存 概念、问题、现象 及 预防问题
常见缓存概念 缓存特征: 命中率、最大元素、清空策略 命中率:命中率返回正确结果数/请求缓存次数 它是衡量缓存有效性的重要指标。命中率越高,表明缓存的使用率越高。 最大元素(最大空间):缓存中可以存放的最大元素的…...
实战项目6(09)
目录 任务场景一 【r1配置】 【r2配置】 【r3配置】 任务场景二 【r1配置】 【r2配置】 【r3配置】 任务场景三 【r1配置】 【r2配置】 【r3配置】 任务场景一 按照下图完成网络拓扑搭建和配置 任务要求:在…...
MySQL 数据库故障排查指南
MySQL 数据库故障排查指南 本指南旨在帮助您识别和解决常见的 MySQL 数据库故障。我们将从问题识别开始,逐步深入到具体的故障类型和排查步骤。 1. 问题识别与信息收集 在开始排查之前,首先需要清晰地了解问题的现象和范围。 故障现象: 数…...
MacOS Python3安装
python一般在Mac上会自带,但是大多都是python2。 python2和python3并不存在上下版本兼容的情况,所以python2和python3可以同时安装在一台设备上,并且python3的一些语法和python2并不互通。 所以在Mac电脑上即使有自带python,想要使…...
锁相放大技术:从噪声中提取微弱信号的利器
锁相放大技术:从噪声中提取微弱信号的利器 一、什么是锁相放大? 锁相放大(Lock-in Amplification)是一种用于检测微弱信号的技术,它能够从强噪声背景中提取出我们感兴趣的特定信号。想象一下在嘈杂的派对上听清某个人…...
机器学习总结
1.BN【batch normalization】 https://zhuanlan.zhihu.com/p/93643523 减少 2.L1L2正则化 l1:稀疏 l2:权重减小 3.泛化误差 训练误差计算了训练集的误差,而泛化误差是计算全集的误差。 4.dropout 训练过程中神经元p的概率失活 一文彻底搞懂深度学习&#x…...
基于神经网络的无源雷达测向系统仿真实现
基于神经网络的无源雷达测向系统仿真实现 项目概述 本项目实现了基于卷积神经网络(CNN)的无源雷达方向到达角(DOA)估计系统。通过深度学习方法,系统能够从接收到的雷达信号中准确估计出信号源的方向,适用于单目标和多目标场景。相比传统的DOA估计算法&…...
《用MATLAB玩转游戏开发》Flappy Bird:小鸟飞行大战MATLAB趣味实现
《用MATLAB玩转游戏开发:从零开始打造你的数字乐园》基础篇(2D图形交互)-Flappy Bird:小鸟飞行大战MATLAB趣味实现 文章目录 《用MATLAB玩转游戏开发:从零开始打造你的数字乐园》基础篇(2D图形交互…...
【C/C++】跟我一起学_C++同步机制效率对比与优化策略
文章目录 C同步机制效率对比与优化策略1 效率对比2 核心同步机制详解与适用场景3 性能优化建议4 场景对比表5 总结 C同步机制效率对比与优化策略 多线程编程中,同步机制的选择直接影响程序性能与资源利用率。 主流同步方式: 互斥锁原子操作读写锁条件变量无锁数据…...
linux 三剑客命令学习
grep Grep 是一个命令行工具,用于在文本文件中搜索打印匹配指定模式的行。它的名称来自于 “Global Regular Expression Print”(全局正则表达式打印),它最初是由 Unix 系统上的一种工具实现的。Grep 工具在 Linux 和其他类 Unix…...
【js基础笔记] - 包含es6 类的使用
文章目录 js基础js 预解析js变量提升 DOM相关知识节点选择器获取属性节点创建节点插入节点替换节点克隆节点获取节点属性获取元素尺寸获取元素偏移量标准的dom事件流阻止事件传播阻止默认行为事件委托 正则表达式js复杂类型元字符 - 基本元字符元字符 - 边界符元字符 - 限定符元…...
《Linux命令行大全(第2版)》PDF下载
内容简介 本书对Linux命令行进行详细的介绍,全书内容包括4个部分,第一部分由Shell的介绍开启命令行基础知识的学习之旅;第二部分讲述配置文件的编辑,如何通过命令行控制计算机;第三部分探讨常见的任务与必备工具&…...
补补表面粗糙度的相关知识(一)
表面粗糙度,或简称粗糙度,是指表面不光滑的特性。这个在机械加工行业内可以说是绝绝的必备知识之一,但往往也是最容易被忽略的,因为往往天天接触的反而不怎么关心,或者没有真正的去认真学习掌握。对于像我一样…...
Python实用工具:pdf转doc
该工具只能使用在英文目录下,且无法转换出图片,以及文本特殊格式。 下载依赖项 pip install PyPDF2 升级依赖项 pip install PyPDF2 --upgrade 查看库版本 python -c "import PyPDF2; print(PyPDF2.__version__)" 下载第二个依赖项 pip i…...
基于Dify实现对Excel的数据分析
在dify部署完成后,大家就可以基于此进行各种应用场景建设,目前dify支持聊天助手(包括对话工作流)、工作流、agent等模式的场景建设,我们在日常工作中经常会遇到各种各样的数据清洗、格式转换处理、数据统计成图等数据分…...
Win全兼容!五五 Excel Word 转 PDF 工具解决多场景转换难题
各位办公小能手们!今天给你们介绍一款超牛的工具——五五Excel Word批量转PDF工具V5.5版。这玩意儿专注搞批量格式转换,能把Excel(.xls/.xlsx)和Word(.doc/.docx)文档唰唰地变成PDF格式。 先说说它的核心功…...
java加强 -Collection集合
集合是一种容器,类似于数组,但集合的大小可变,开发中也非常常用。Collection代表单列集合,每个元素(数据)只包含1个值。Collection集合分为两类,List集合与set集合。 特点 List系列集合&#…...
BGP实验练习1
需求: 要求五台路由器的环回地址均可以相互访问 需求分析: 1.图中存在五个路由器 AR1、AR2、AR3、AR4、AR5,分属不同自治系统(AS),AR1 在 AS 100,AR2 - AR4 在 AS 200,AR5 在 AS …...
Nginx location静态文件映射配置
遇到问题? 以下这个Nginx的配置,愿意为访问https://abc.com会指向一个动态网站,访问https://abc.com/tongsongzj时会访问静态网站,但是配置之后(注意看后面那个location /tongsongzj/静态文件映射的配置)&…...
四、Hive DDL表定义、数据类型、SerDe 与分隔符核心
在理解了 Hive 数据库的基本操作后,本篇笔记将深入到数据存储的核心单元——表 (Table) 的定义和管理。掌握如何创建表、选择合适的数据类型、以及配置数据的读写方式 (特别是 SerDe 和分隔符),是高效使用 Hive 的关键。 一、创建表 (CREATE TABLE)&…...
每日脚本 5.11 - 进制转换和ascii字符
前置知识 python中各个进制的开头 二进制 : 0b 八进制 : 0o 十六进制 : 0x 进制转换函数 : bin() 转为2进制 oct() 转换为八进制的函数 hex() 转换为16进制的函数 ascii码和字符之间的转换 : chr(97) 码转为字符 …...
cookie和session的区别
一、基本概念 1. Cookie 定义:Cookie 是服务器发送到用户浏览器并保存在本地的一小块数据(通常小于4KB),浏览器会在后续请求中自动携带该数据。作用:用于跟踪用户状态(如登录状态)、记…...
Kotlin Multiplatform--03:项目实战
Kotlin Multiplatform--03:项目实战 引言配置iOS开发环境配置项目环境运行程序 引言 本章将会带领读者进行项目实战,了解如何从零开始编译一个能同时在Android和iOS运行的App。开发环境一般来说需要使用Macbook,笔者没试过Windows是否能开发。…...
图形学、人机交互、VR/AR领域文献速读【持续更新中...】
(1)笔者在时间有限的情况下,想要多积累一些自身课题之外的新文献、新知识,所以开了这一篇文章。 (2)想通过将文献喂给大模型,并向大模型提问的方式来快速理解文献的重要信息(如基础i…...
opencascade.js stp vite 调试笔记
Hello, World! | OpenCascade.js cnpm install opencascade.js cnpm install vite-plugin-wasm --save-dev 当你不知道文件写哪的时候trae还是有点用的 ‘’‘ import { defineConfig } from vite; import wasm from vite-plugin-wasm; import rollupWasm from rollup/plugi…...
openharmony系统移植之gpu mesa3d适配
openharmony系统移植之gpu mesa3d适配 文章目录 openharmony系统移植之gpu mesa3d适配1. 环境说明2. gpu内核panfrost驱动2.1 使能panfrost驱动2.2 panfrost dts配置 3. buildroot下测试gpu驱动3.1 buildroot配置编译 4. ohos下mesa3d适配4.1 ohos下mesa3d编译调试4.1.2 编译4.…...
Java开发经验——阿里巴巴编码规范经验总结2
摘要 这篇文章是关于Java开发中阿里巴巴编码规范的经验总结。它强调了避免使用Apache BeanUtils进行属性复制,因为它效率低下且类型转换不安全。推荐使用Spring BeanUtils、Hutool BeanUtil、MapStruct或手动赋值等替代方案。文章还指出不应在视图模板中加入复杂逻…...
Linux中常见开发工具简单介绍
目录 apt/yum 介绍 常用命令 install remove list vim 介绍 常用模式 命令模式 插入模式 批量操作 底行模式 模式替换图 vim的配置文件 gcc/g 介绍 处理过程 预处理 编译 汇编 链接 库 静态库 动态库(共享库) make/Makefile …...
深入理解深度Q网络DQN:基于python从零实现
DQN是什么玩意儿? 深度Q网络(DQN)是深度强化学习领域里一个超厉害的算法。它把Q学习和深度神经网络巧妙地结合在了一起,专门用来搞定那些状态空间维度特别高、特别复杂的难题。它展示了用函数近似来学习价值函数的超能力…...