- 人工智能
- 语音
- 音频
【免费下载链接】PaddleSpeech
Easy-to-use Speech Toolkit including Self-Supervised Learning model, SOTA/Streaming ASR with punctuation, Streaming TTS with text frontend, Speaker Verification System, End-to-End Speech Translation and Keyword Spotting. Won NAACL2022 Best Demo Award.
导读
本文以 PaddleSpeech 仓库中的demos/TTSCppFrontend为对象,系统讲解如何在 C++ 侧实现 TTS(语音合成)的文本前端(Frontend):即把中文文本经过繁简转换、分句、分词、文本正则化、音素映射、变调与儿化音处理后,转换为声学模型可直接消费的音素序号数组。读者读完本文后,将掌握该 demo 的编译环境准备、构建流程、词典下载、配置项详解、运行方式与输出含义,并理解其底层ppspeech::FrontEngineInterface的完整调用链与实现原理,为在自有 C++ TTS 服务中接入文本前端打下基础。
一、TTSCppFrontend 是什么
TTS 系统的完整链路通常包含「文本前端 → 声学模型 → 声码器」三大部分。其中文本前端负责将自然语言文本转换为声学模型能够理解的音素序列,是决定合成音质与可懂度的第一步。
PaddleSpeech 在demos/TTSCppFrontend目录下提供了一个纯 C++ 实现的 TTS 文本前端 demo,其核心功能是 text-to-phoneme(文本转音素)转换。它复用了与 Python 侧 TTS 前端相同的处理策略,并依赖 cppjieba 分词与一组词典文件完成全流程处理,最终输出与 PaddleSpeech 的 FastSpeech2 / Speedyspeech 声学模型字典格式对齐的音素 id 数组(phoneids)与音调 id 数组(toneids)。
当前版本存在一个明确的限制(README 已注明):仅支持中文,输入任意英文单词会导致 demo 崩溃。因此在评测与使用时应只输入中文文本(含中文标点)。
二、整体结构速览
demos/TTSCppFrontend/ ├── CMakeLists.txt # 顶层构建脚本(静态库 + demo 可执行文件) ├── build.sh # 一键构建脚本 ├── clean.sh # 清理脚本 ├── download.sh # 下载词典与依赖 ├── run_front_demo.sh # 运行 demo ├── front_demo/ │ ├── front.conf # 前端配置文件(jieba/词典路径等) │ ├── front_demo.cpp # demo 主程序入口 │ └── gentools/ # 字典生成工具(genid.py 等) ├── src/ │ ├── base/type_conv.{h,cpp} # utf8/wstring 转换 │ └── front/ │ ├── front_interface.{h,cpp} # 前端引擎核心实现 │ └── text_normalize.{h,cpp} # 文本正则化 └── third-party/CMakeLists.txt # 第三方依赖(gflags/glog/abseil/cppjieba/limonp)其中代码核心是 front_interface.h 与 front_interface.cpp 中的ppspeech::FrontEngineInterface,它继承自 text_normalize.h 中的TextNormalizer(负责正则化),并在此基础上叠加分词、音素映射与变调逻辑。
三、安装构建工具
构建需要 C++17 编译环境与 CMake,README 给出了 Ubuntu 与 CentOS 两种安装方式:
# Ubuntu sudo apt install build-essential cmake pkg-config # CentOS sudo yum groupinstall "Development Tools" sudo yum install cmake如果系统的 cmake 版本过旧(顶层 CMakeLists.txt 要求cmake_minimum_required(VERSION 3.10)),可以到 cmake 官网下载预编译的新版本替代系统自带版本。
四、构建流程与第三方依赖
4.1 一键构建
# 使用全部 CPU 核心并行构建 ./build.sh # 仅使用 1 个核心构建 ./build.sh -j1构建产物为build/tts_front_demo可执行文件。依赖库会自动下载到third-party/build目录。若下载速度过慢,可打开 third-party/CMakeLists.txt 修改GIT_REPOSITORY为可访问的镜像地址。
4.2 依赖清单与链接方式
从 third-party/CMakeLists.txt 可以看到以下依赖:
| 依赖 | 版本 | 作用 | 引入方式 |
|---|---|---|---|
| gflags | v2.2.2 | 命令行参数解析 | pkg-config +IMPORTED_TARGET |
| glog | v0.6.0 | 日志输出 | pkg-config +IMPORTED_TARGET |
| abseil-cpp | 20230125.1 | 字符串处理(absl::StrSplit等) | pkg-config +IMPORTED_TARGET |
| cppjieba | v5.0.3 | 中文分词(header-only) | include 头文件 |
| limonp | v0.6.6 | 基础工具库(header-only,cppjieba 依赖) | include 头文件 |
顶层 CMakeLists.txt 的关键点:
- 通过
ENV{PKG_CONFIG_PATH}指向third-party/build下的 pkgconfig 目录,并使用pkg_check_modules加载 gflags/glog/abseil; - 将
src/base/*.cpp与src/front/*.cpp编译为静态库paddlespeech_tts_front(CMAKE_CXX_STANDARD 17、POSITION_INDEPENDENT_CODE ON); - 通过
WITH_FRONT_DEMO(默认 ON)选项控制是否编译tts_front_demo可执行文件,其源码来自front_demo/*.cpp并链接paddlespeech_tts_front。
五、下载词典文件
构建完成后,需要下载前端运行所需的词典文件:
./download.sh从 download.sh 可以看到,脚本会下载 4 个压缩包到front_demo/dict目录,并通过 MD5 校验完整性(文件已存在且 MD5 匹配时自动跳过):
| 压缩包 | 内容 | MD5 |
|---|---|---|
fastspeech2_nosil_baker_ckpt_0.4.tar.gz | FastSpeech2 前端字典(word2phone_fs2.dict、phone_id_map.txt 等) | 7bf1bab1737375fa123c413eb429c573 |
speedyspeech_nosil_baker_ckpt_0.5.tar.gz | Speedyspeech 前端字典(word2phone.dict、tone_id_map.txt 等) | 0b7754b21f324789aef469c61f4d5b8f |
jieba.tar.gz | cppjieba 分词词典(jieba.dict.utf8、hmm_model.utf8 等 5 个文件) | 6d30f426bd8c0025110a483f051315ca |
tranditional_to_simplified.tar.gz | 繁转简字典(trand2simp.txt) | 258f5b59d5ebfe96d02007ca1d274a7f |
下载后的目录结构形如:
front_demo/dict/ ├── fastspeech2_nosil_baker_ckpt_0.4/ │ ├── word2phone_fs2.dict │ ├── phone_id_map.txt │ └── ... ├── speedyspeech_nosil_baker_ckpt_0.5/ │ ├── word2phone.dict │ ├── phone_id_map.txt │ ├── tone_id_map.txt │ └── ... ├── jieba/ │ ├── jieba.dict.utf8 │ ├── hmm_model.utf8 │ ├── user.dict.utf8 │ ├── idf.utf8 │ └── stop_words.utf8 └── tranditional_to_simplified/ └── trand2simp.txt注意download.sh使用wget,若系统未安装 wget 需提前安装。
六、运行 demo
6.1 基本用法
./run_front_demo.sh ./run_front_demo.sh --help ./run_front_demo.sh --sentence "这是语音合成服务的文本前端,用于将文本转换为音素序号数组。" ./run_front_demo.sh --front_conf ./front_demo/front.conf --sentence "你还需要一个语音合成后端才能将其转换为实际的声音。"run_front_demo.sh 内部逻辑很简单:切换到脚本所在目录并执行./build/tts_front_demo "$@",即把全部命令行参数透传给 demo 程序(set -e保证出错即退出)。
6.2 命令行参数
从 front_demo.cpp 的 gflags 定义可以看到 demo 支持两个参数:
| 参数 | 默认值 | 说明 |
|---|---|---|
--sentence | 你好,欢迎使用语音合成服务 | 待合成的文本 |
--front_conf | ./front_demo/front.conf | 前端配置文件路径 |
--help由 gflags 自动提供(ParseCommandLineFlags)。
6.3 输出说明
demo 会把每个分句的原始文本、正则化后的文本、以及最终的 phoneids 与 toneids 通过 glog 打印到日志。例如处理分句后:
I... The phoneids of the sentence is: 67 45 12 10 ... 42 0 I... The toneids of the sentence is:其中 phoneids 是音素 id 数组(FastSpeech2 模式),toneids 在separate_tone=false(FastSpeech2)时为空,在separate_tone=true(Speedyspeech)时为音调 id 数组。标点会被映射为sp(FastSpeech2)或sp0(Speedyspeech)静音音素,其 id 也包含在输出中。这个数组即可作为声学模型(如 FastSpeech2 / Speedyspeech)的输入特征。
七、配置文件 front.conf 详解
配置文件 front.conf 是前端引擎的灵魂,其读取逻辑位于FrontEngineInterface::ReadConfFile()(front_interface.cpp):逐行扫描以--开头的行,按第一个=拆分为 key/value 存入conf_map。因此新增配置项只需按同样格式追加一行。
7.1 jieba 分词配置
--jieba_dict_path=./front_demo/dict/jieba/jieba.dict.utf8 --jieba_hmm_path=./front_demo/dict/jieba/hmm_model.utf8 --jieba_user_dict_path=./front_demo/dict/jieba/user.dict.utf8 --jieba_idf_path=./front_demo/dict/jieba/idf.utf8 --jieba_stop_word_path=./front_demo/dict/jieba/stop_words.utf8这 5 个路径按顺序对应 cppjieba::Jieba 构造函数的 5 个参数(front_interface.cpp),缺一不可。其中user.dict.utf8可用于加入自定义词汇(如领域专有名词)提升分词准确度。
7.2 音素字典配置(FastSpeech2 为例,默认启用)
--separate_tone=false --word2phone_path=./front_demo/dict/fastspeech2_nosil_baker_ckpt_0.4/word2phone_fs2.dict --phone2id_path=./front_demo/dict/fastspeech2_nosil_baker_ckpt_0.4/phone_id_map.txt --tone2id_path=./front_demo/dict/fastspeech2_nosil_baker_ckpt_0.4/word2phone_fs2.dict7.3 音素字典配置(Speedyspeech,被注释,按需启用)
#--separate_tone=true #--word2phone_path=./front_demo/dict/speedyspeech_nosil_baker_ckpt_0.5/word2phone.dict #--phone2id_path=./front_demo/dict/speedyspeech_nosil_baker_ckpt_0.5/phone_id_map.txt #--tone2id_path=./front_demo/dict/speedyspeech_nosil_baker_ckpt_0.5/tone_id_map.txt7.4 繁简转换配置
--trand2simpd_path=./front_demo/dict/tranditional_to_simplified/trand2simp.txt各配置项的作用与影响如下:
| 配置项 | 必填 | 说明 |
|---|---|---|
jieba_dict_path等 5 项 | 是 | cppjieba 词典路径,缺任一文件初始化即失败 |
separate_tone | 是 | true表示音调与音素分离输出(Speedyspeech 风格,toneids 非空);false表示音素直接含调(FastSpeech2 风格,toneids 为空)。注意tone2id_path仅在true时才会被加载(见init()中if (_separate_tone == "true")分支) |
word2phone_path | 是 | 词→音素映射字典,分词结果中未命中的词会退回jieba->CutAll全切分后逐词查表(GetPhone) |
phone2id_path | 是 | 音素→音素 id 映射字典。README 提示:可以改成你自己声学模型的phone_id_map.txt,实现前端与自定义声学模型的对接 |
tone2id_path | 仅 Speedyspeech | 音调→音调 id 映射 |
trand2simpd_path | 是 | 繁体→简体逐字映射字典,用于Trand2Simp |
八、工作流程与源码级原理
8.1 demo 主程序调用链
front_demo.cpp 展示了完整的调用流程:
- 以
--front_conf路径构造ppspeech::FrontEngineInterface(构造函数内部自动调用init()); Trand2Simp:逐字符查繁简字典,将繁体字替换为简体;SplitByPunc:按标点切分句子(标点集合见init()中的_punc,包含,。、?:;~!, . ? ! : ; / \等;_punc_omit中的引号类标点会被忽略);- 对每个分句执行
SentenceNormalize(文本正则化,来自父类TextNormalizer); GetSentenceIds:对分句分词并生成 phoneids/toneids;- 打印最终的音素与音调 id 数组。
8.2 音素 id 生成的核心逻辑
GetSentenceIds→Cut→GetWordsIds的链路(front_interface.cpp)是文本前端的主干:
- Cut(分词):
_jieba->Tag(sentence, ...)得到「词 + 词性」结果,再经MergeforModify对分词结果做 7 步合并处理:MergeBu(含“不”词合并)→Mergeyi(含“一”词合并)→MergeReduplication(叠词合并)→MergeThreeTones/MergeThreeTones2(连续第三声合并)→MergeEr(“儿”字与前词合并)。这些合并是为了给后续变调规则提供正确的词边界。 - GetInitialsFinals:通过
GetPhone查word_phone_map得到词的音素串,再按规则拆分为「声母列表 + 韵母列表」;若词不在字典中,则用_jieba->CutAll全切分后逐词查表拼接。 - ModifyTone(变调):依次执行
BuSandi(“不”的变调,如不 + 四声 → bú)、YiSandhi(“一”的变调,如四声前读二声、非四声前读四声、叠词间读轻声)、NeuralSandhi(轻声处理,内置must_neural_tone_words/must_not_neural_tone_words两个词表,覆盖量词、语气词、方位词、“的/地/得”、“了/着/过”、叠词名词动词等场景)、ThreeSandhi(三声变调,双音节词前字变二声,三/四字词按 2+1 或 1+2 切分后递归处理)。 - MergeErhua(儿化音):对词尾为“儿”且前字非免儿化词(内置
must_erhua/not_erhua词表)的情况,在韵母中插入r,如er2 → er2变为带卷舌色彩的韵母。 - Phone2Phoneid:将音素串按空格切分,逐项查
phone_id_map得到 id。separate_tone=true时按「音素本体 + 最后一个数字音调」拆分,分别查phone_id_map与tone_id_map(见 front_interface.cpp)。 - 标点处理:标点统一映射为
sp(FastSpeech2)或sp0(Speedyspeech)静音音素,再查 id 表。
8.3 文本正则化(TextNormalizer)
父类 text_normalize.h 中声明的SentenceNormalize及一系列Re*方法(ReData日期、ReTime时间、RePercentage百分比、RePhone电话号码、ReMobilePhone手机号、ReFrac分数、ReRange范围、ReInterger整数、ReDecimalNum小数、ReTemperature温度、RePositiveQuantifiers量词等)负责把数字、日期、时间等非文字符号展开为中文读音,与 Python 侧 TTS 前端的文本正则化策略对齐。demo 会在GetSentenceIds前调用SentenceNormalize,保证“2023年5月1日”之类的文本能被正确读音化。
8.4 配置解析细节
ReadConfFile只接受--key=value形式的行;以#开头的注释行会被getline读到但因其不以--开头而被跳过(这也是front.conf中用#注释 Speedyspeech 配置块的原因)。加载顺序为:jieba 5 项 → separate_tone → word2phone → phone2id → tone2id(仅 separate_tone=true 时)→ trand2simpd(front_interface.cpp)。
九、对接自定义声学模型
README 明确指出:可以通过修改front.conf中的--phone2id_path指向你自己的声学模型的phone_id_map.txt,让该前端输出的音素 id 直接匹配自定义模型。操作步骤:
- 下载并解压词典(
./download.sh); - 将 front.conf 中的
phone2id_path改为目标模型的phone_id_map.txt; - 若目标模型为 Speedyspeech 风格(音素与音调分离),同时设置
--separate_tone=true并指定tone2id_path; - 重新运行
./run_front_demo.sh --sentence "..."验证输出 id 是否在目标模型 id 空间内。
若需按新字典生成 id 映射文件,可参考front_demo/gentools/下的工具:genid.py从phones.txt/tones.txt生成<pad> 0、<unk> 1起序的 id 字典文件;word2phones.py与gen_dict_paddlespeech.py用于生成词到音素的映射字典。
十、清理
./clean.sh该命令会删除front_demo/dict、build与third-party/build三个目录(即词典、构建产物与第三方依赖全部清除)。清理后如需重新使用,需重新执行./download.sh与./build.sh。
十一、已知限制与使用建议
- 仅支持中文:README 明确提示任何英文单词都会导致 demo 崩溃,实际使用时应先做语言过滤;
- 词典依赖外网下载:
download.sh使用 wget 从 bcebos CDN 下载,网络受限环境可手动下载后按目录结构放置,并核对 MD5; - 音素字典对齐:输出 id 的语义完全取决于
phone2id_path所指字典,对接不同声学模型前务必确认字典一致,否则会出现「前端输出 id 与模型字典错位」的问题; - 路径相对性:
front.conf中所有路径均为相对路径,运行时需保持「脚本所在目录为工作目录」(run_front_demo.sh已自动cd,若直接执行build/tts_front_demo需自行保证路径正确)。
十二、小结
PaddleSpeech 的demos/TTSCppFrontend提供了一个可独立编译、可复用的 C++ TTS 文本前端参考实现:它完整覆盖了中文文本从繁简转换、分句、正则化、jieba 分词、音素查表、变调与儿化音处理到输出 phoneids/toneids 的全部环节,且通过front.conf将词典路径与声学模型字典解耦,便于对接 FastSpeech2 / Speedyspeech 乃至自定义声学模型。开发者可以以此为模板,在自有 C++ TTS 服务中集成paddlespeech_tts_front静态库,或将其中的变调、儿化音、文本正则化等规则移植到其他工程。
- 人工智能
- 语音
- 音频
【免费下载链接】PaddleSpeech
Easy-to-use Speech Toolkit including Self-Supervised Learning model, SOTA/Streaming ASR with punctuation, Streaming TTS with text frontend, Speaker Verification System, End-to-End Speech Translation and Keyword Spotting. Won NAACL2022 Best Demo Award.
相关推荐
FunASR 中文文本正则化(Text Normalization)完整指南:从口语化数字到 TTS 前端文本
FunASR 中文文本正则化(Text Normalization)完整指南:从口语化数字到 TTS 前端文本 导读 本文以 FunASR 仓库中 fun_te
语音音频人工智能大模型模型推理服务本地部署5分钟上手PaddleSpeech TTS:从文本到语音的全流程实践指南
5分钟上手PaddleSpeech TTS:从文本到语音的全流程实践指南 你还在为开发语音交互功能时遇到的合成语音生硬、多语言支持不足、部署流程复杂等问题而困扰
人工智能语音音频PaddleSpeech 文本转语音(TTS)功能详解与使用指南
PaddleSpeech 文本转语音 TTS 功能详解与使用指南 一、文本转语音技术概述 文本转语音 Text to Speech, TTS 是一种将书面文字转
人工智能语音音频
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考