🐸TTS Vocoder 训练实战:从配置 MelGAN / ParallelWaveGAN 到续训与微调的完整流程
本文以 TTS/vocoder/README.md 为主线,系统讲解 🐸TTS 仓库中 Vocoder 模块的训练方法:如何准备数据、编写 config.json、用 train_vocoder.py 启动训练、续训(continue)与微调(restore)的区别,并深入源码剖析 GAN 训练循环中生成器/判别器交替更新、多损失组合与 PQMF 分带处理的实现细节,帮助你在真实语料上独立训练并复现 MelGAN、ParallelWaveGAN 等声码器。
一、Vocoder 模块的定位与模型清单
TTS/vocoder/README.md 开篇即点明:该目录实现了一批声码器(vocoder)模型,它们可以与其他 TTS 模型组合使用——即 TTS 声学模型负责输出 mel 频谱,Vocoder 负责把频谱还原为波形。README 列出的早期实现为:
- MelGAN
- MultiBand-MelGAN
- ParallelWaveGAN
- GAN-TTS(当时仅实现了 Discriminator 部分)
从当前仓库的实际结构看,模型清单已经明显扩大。TTS/vocoder/configs/ 目录下提供了 8 套独立配置(melgan_config.py、multiband_melgan_config.py、parallel_wavegan_config.py、hifigan_config.py、univnet_config.py、wavernn_config.py、wavegrad_config.py、fullband_melgan_config.py),TTS/vocoder/models/ 目录下则对应实现了各模型的 generator 与 discriminator 类,例如 melgan_generator.py、hifigan_discriminator.py、univnet_generator.py 等。README 还特别强调该框架“灵活且模块化(but not too modular)”——这一点在模型加载机制上有直接体现(见第五节 setup_model)。
二、训练数据准备:把 wav 文件收进一个目录即可
README 给出的第一步非常直接:把所有 wav 文件收拢到一个文件夹,然后把该文件夹路径填入 config.json 的 data_path。这一步在源码中的对应实现是 TTS/vocoder/datasets/preprocess.py:
def find_wav_files(data_path, file_ext="wav"):
wav_paths = glob.glob(os.path.join(data_path, "**", f"*.{file_ext}"), recursive=True)
return wav_paths
也就是说,data_path 下的 wav 文件会被递归查找,不需要扁平结构。训练/验证集切分同样在这里完成:
def load_wav_data(data_path, eval_split_size, file_ext="wav"):
wav_paths = find_wav_files(data_path, file_ext=file_ext)
assert len(wav_paths) > 0, f" [!] {data_path} is empty."
np.random.seed(0)
np.random.shuffle(wav_paths)
return wav_paths[:eval_split_size], wav_paths[eval_split_size:]
两点值得注意:
- 切分使用固定随机种子 0(
np.random.seed(0)),因此同一数据集每次启动训练时的 train/eval 划分是一致的,便于对比实验; eval_split_size指定用于评估的样本数(默认 10,定义于 shared_configs.py 的BaseVocoderConfig),其余全部参与训练。
如果不想在线计算 mel 特征,还可以走预计算特征路径:训练入口 TTS/bin/train_vocoder.py 中,当 config 存在非空的 feature_path 时会调用 load_wav_feat_data(config.data_path, config.feature_path, config.eval_split_size),该函数会按文件名(stem)把 wav 与 .npy 特征文件一一配对,并断言二者数量与命名一致。这一分支主要服务于需要量化波形特征的模型(如 WaveRNN,见 preprocess.py 中的 preprocess_wav_files)。
三、配置文件体系:三个层次继承下来的参数表
Vocoder 配置采用 dataclass + coqpit 的层次化设计,全部继承链为:
BaseTrainingConfig (TTS.config)
└── BaseVocoderConfig # 所有声码器共享
└── BaseGANVocoderConfig # GAN 类声码器共享
├── MelganConfig / ParallelWaveganConfig / HifiganConfig / ...
3.1 BaseVocoderConfig:数据加载与基础训练参数
定义于 TTS/vocoder/configs/shared_configs.py,核心字段及默认值如下:
| 参数 | 类型/默认值 | 说明 |
|---|---|---|
audio |
BaseAudioConfig |
音频处理器配置(采样率、mel 参数等),训练时据此构建 AudioProcessor |
data_path |
"" |
训练数据根目录,递归查找全部 wav |
feature_path |
None |
预计算特征目录;留空则在线计算特征 |
seq_len |
1000 |
训练时截取的声音片段长度(各模型会覆盖,如 MelGAN 为 8192) |
pad_short |
0 |
对短于 seq_len 的波形的额外 padding |
conv_pad |
0 |
针对频谱边缘卷积的额外 padding |
use_noise_augment |
False |
是否对输入添加随机噪声增强 |
use_cache |
False |
是否把计算好的特征缓存在内存中,RAM 不足可能 OOM |
eval_split_size |
10 |
评估样本数 |
epochs |
10000 |
训练总轮数 |
optimizer |
"AdamW" |
优化器名称 |
optimizer_params |
{"betas": [0.8, 0.99], "weight_decay": 0.0} |
优化器超参,注意默认 betas 是 (0.8, 0.99) 而非 (0.9, 0.999) |
3.2 BaseGANVocoderConfig:GAN 训练与损失组合的“开关面板”
GAN 类声码器的训练完全由一组开关 + 权重控制。每个 use_* 布尔位决定是否启用某项损失,对应的 *_loss_weight 负责加权求和:
| 开关 | 默认 | 对应权重(默认) | 损失来源 |
|---|---|---|---|
use_stft_loss |
True | stft_loss_weight = 0 |
ParallelWaveGAN 提出的多分辨率 STFT 损失 |
use_subband_stft_loss |
True | subband_stft_loss_weight = 0 |
MultiBand-MelGAN 的分带 STFT 损失 |
use_mse_gan_loss |
True | mse_G_loss_weight = 1 |
MSE 型 GAN 损失 |
use_hinge_gan_loss |
True | hinge_G_loss_weight = 0 |
Hinge GAN 损失(与 MSE 二选一) |
use_feat_match_loss |
True | feat_match_loss_weight = 100 |
MelGAN 的特征匹配损失(依赖能输出中间特征的判别器) |
use_l1_spec_loss |
True | l1_spec_loss_weight = 45 |
HiFi-GAN 的 L1 频谱(mel)损失 |
STFT 损失的多分辨率参数默认为 {"n_ffts": [1024, 2048, 512], "hop_lengths": [120, 240, 50], "win_lengths": [600, 1200, 240]};L1 频谱损失默认在 mel 域计算(n_mels: 80, hop_length: 256, n_fft: 1024,采样率 22050)。
除损失外,BaseGANVocoderConfig 还定义了 GAN 训练特有的优化器与调度器参数:lr_gen = 0.0002、lr_disc = 0.0002,各自的 ExponentialLR 学习率调度器(gamma = 0.999,scheduler_after_epoch = True),梯度裁剪 grad_clip = [5, 5](对两个优化器各设阈值),以及两个训练策略开关:
steps_to_start_discriminator(默认 0):前若干步只训生成器、推迟判别器启动;diff_samples_for_G_and_D(默认 False):让判别器使用与生成器不同的样本对,迭代变慢但某些情况下收敛更好;use_pqmf(默认 False):启用 PQMF 进行多分带训练(MultiBand-MelGAN 使用)。
3.3 以 MelganConfig 为例的完整配置
以 TTS/vocoder/configs/melgan_config.py 为例,它在上层开关基础上的默认值给出了一个可直接复用的训练起点:
@dataclass
class MelganConfig(BaseGANVocoderConfig):
model: str = "melgan"
discriminator_model: str = "melgan_multiscale_discriminator"
discriminator_model_params: dict = field(
default_factory=lambda: {"base_channels": 16, "max_channels": 1024, "downsample_factors": [4, 4, 4, 4]}
)
generator_model: str = "melgan_generator"
generator_model_params: dict = field(
default_factory=lambda: {"upsample_factors": [8, 8, 2, 2], "num_res_blocks": 3}
)
batch_size: int = 16
seq_len: int = 8192
pad_short: int = 2000
use_noise_augment: bool = True
use_cache: bool = True
# 损失组合:STFT + MSE-GAN + 特征匹配;关闭 hinge 与 subband
use_stft_loss: bool = True
use_subband_stft_loss: bool = False
use_mse_gan_loss: bool = True
use_hinge_gan_loss: bool = False
use_feat_match_loss: bool = True
stft_loss_weight: float = 0.5
mse_G_loss_weight: float = 2.5
feat_match_loss_weight: float = 108
可以看到 MelGAN 的默认组合是「STFT 损失(0.5) + MSE-GAN(2.5) + 特征匹配(108)」,并开启了噪声增强与特征缓存。ParallelWaveganConfig 则默认使用 parallel_wavegan_discriminator 与 parallel_wavegan_generator(upsample_factors [4,4,4,4]、stacks 3、num_res_blocks 30 等,见 parallel_wavegan_config.py 的文档串)。各配置的字段注释本身就是一份参数手册,建议训练前通读对应 dataclass。
如果你想要现成的完整 config.json 起点,除了 TTS/vocoder/configs/ 外,recipes/ljspeech/ 下为每个模型都提供了配方脚本(如 hifigan/train_hifigan.py、multiband_melgan/train_multiband_melgan.py),可以直接参考其中的参数组合。
四、训练、续训与微调:三条命令的语义差异
README 给出的核心操作如下(仓库中该入口脚本实际位于 TTS/bin/train_vocoder.py):
1. 新起一次训练——先准备 config.json,然后:
CUDA_VISIBLE_DEVICES='0' python TTS/bin/train_vocoder.py --config_path path/to/config.json
2. 从上次训练中断处继续(continue):
CUDA_VISIBLE_DEVICES='0' python TTS/bin/train_vocoder.py --continue_path path/to/your/model/folder
3. 用预训练权重微调(restore):
CUDA_VISIBLE_DEVICES='0' python TTS/bin/train_vocoder.py --restore_path path/to/your/model.pth
README 对后两条命令的差异有一句关键说明,值得逐字理解:
Restoring a model starts a new training in a different folder. It only restores model weights with the given checkpoint file. However, continuing a training starts from the same directory where the previous training run left off.
即:restore 只恢复模型权重、在新目录开一次全新训练(优化器状态、步数计数等不继承);continue 则原地继续,从上次留下的目录接着跑。这一行为在源码中得到印证:TTS/bin/train_vocoder.py 中 --config_path 走 load_config(args.config_path),--continue_path 则读取 <continue_path>/config.json——后者依赖训练器在实验目录下回写的配置,这正是“原地继续”的实现基础。
启动入口 main() 的完整流程为:
- 解析命令行参数(
TrainVocoderArgs,允许用额外的--xxx覆盖 config 中的字段,见parser.parse_known_args与config.parse_known_args(config_overrides, relaxed_parser=True)); - 按
feature_path是否存在选择load_wav_feat_data或load_wav_data载入样本; - 用
AudioProcessor(**config.audio)构建音频处理器; - 通过
setup_model(config)依据配置实例化模型; - 交给通用
Trainer并执行trainer.fit(),同时把audio_processor作为training_assets传入(供训练日志画图、合成试听音频)。
README 最后还提示:训练过程与 TTS 模型一样,可以通过 Tensorboard 跟踪——日志由 Trainer 的 logger 统一写出,GAN.train_log / GAN.eval_log 会在每个评估周期调用 plot_results(TTS/vocoder/utils/generic_utils.py)绘制预测波形/频谱对比图,并保存一条试听音频(见 gan.py 的 _log 方法)。
五、框架纵深:模型如何被动态装配,GAN 训练循环如何运转
5.1 “灵活且模块化”的模型装载机制
README 提到适配新声码器很容易,这对应 TTS/vocoder/models/init.py 中基于配置名的动态导入:
def setup_model(config: Coqpit):
if "discriminator_model" in config and "generator_model" in config:
MyModel = importlib.import_module("TTS.vocoder.models.gan")
MyModel = getattr(MyModel, "GAN")
else:
MyModel = importlib.import_module("TTS.vocoder.models." + config.model.lower())
...
return MyModel.init_from_config(config)
也就是说:只要配置里同时声明了 discriminator_model 与 generator_model,就一律走统一的 GAN 包装类,其余单模型(WaveRNN、Wavegrad 等)则按 config.model 字符串映射到 models/ 下的同名模块。setup_generator / setup_discriminator 再按 generator_model / discriminator_model 的字符串名实例化具体网络,并把 generator_model_params / discriminator_model_params 展开为构造参数——这正是“mix and match”的落点:你可以用 HifiganConfig 的生成器换配 MelGAN 系判别器,而不用改任何训练代码。
所有声码器模型继承 TTS/vocoder/models/base_vocoder.py 中的 BaseVocoder,其约定:
MODEL_TYPE = "vocoder",标识模型类别;- 输入/输出张量形状规范:
batch x time x channels(3D)、batch x channels(2D)、batch x 1(1D); _set_model_args会区分*Config(训练用,参数嵌在config.model_args中)与*Args(纯推理配置)两种 config 形态。
5.2 GAN 训练循环:一次 train_step 里发生了什么
GAN 类声码器的核心是 TTS/vocoder/models/gan.py 中的 GAN 类。它把 generator(model_g)与 discriminator(model_d)包在一个 Lightning 兼容的模型里,通过 optimizer_idx 区分当前是判别器还是生成器优化步:
optimizer_idx == 0(判别器步):先用生成器前向得到y_hat并缓存(self.y_hat_g);若diff_samples_for_G_and_D开启,则用 batch 中额外提供的input_disc / waveform_disc样本重新跑一次生成器(no_grad);随后用真/假样本对调用判别器,取(scores_fake, scores_real)计算判别器损失。判别器是否带条件输入通过反射检查forward参数个数(2 个参数即条件判别器,如 UnivNet)自动适配。optimizer_idx == 1(生成器步):复用缓存的y_hat_g过判别器得到scores_fake(及特征feats_fake),若启用特征匹配损失则以no_grad过一遍真样本得到feats_real,最后统一交给GeneratorLoss按配置中的开关组合出总损失。- PQMF 多分带处理:当生成器输出通道数 > 1(如 MultiBand-MelGAN 输出 4 个带),代码自动调用
model_g.pqmf_synthesis(y_hat)合成回单声道波形再喂给判别器,并对真波形做pqmf_analysis得到分带目标——这就是配置里use_pqmf选项背后的机制,分带相关层实现在 TTS/vocoder/layers/pqmf.py。 - 延迟启动判别器:
on_train_step_start中self.train_disc = trainer.total_steps_done >= self.config.steps_to_start_discriminator,在训练早期只训生成器,实现“热身”策略。 - 优化器顺序:
get_optimizer返回[optimizer2(disc), optimizer1(gen)],与train_step中optimizer_idx的语义(0=判别器,1=生成器)严格对齐;调度器通过lr_scheduler_gen / lr_scheduler_disc分别构建。 - 损失组合:
get_criterion返回[DiscriminatorLoss(config), GeneratorLoss(config)],二者均实现在 TTS/vocoder/layers/losses.py,按第三节表格中的开关与权重把 STFT / Subband-STFT / MSE-GAN / Hinge-GAN / 特征匹配 / L1 频谱损失加权求和。
数据侧,GAN.get_data_loader 构建 GANDataset,透传 seq_len、pad_short、conv_pad、use_noise_augment、use_cache 等配置;当 diff_samples_for_G_and_D 开启时,return_pairs=True 让数据集每次返回两对样本(G 用与 D 用各一份),format_batch 则把 (x_G, y_G, x_D, y_D) 整理成 {"input", "waveform", "input_disc", "waveform_disc"} 供 train_step 消费。
六、验证与测试:如何确认你的训练在正常工作
仓库为声码器模块准备了成体系的测试,位于 tests/vocoder_tests/,例如:
- test_melgan_train.py、test_parallel_wavegan_train.py、test_multiband_melgan_train.py、test_hifigan_train.py:端到端跑训练流程;
- test_vocoder_melgan_generator.py、test_vocoder_melgan_discriminator.py、test_vocoder_parallel_wavegan_discriminator.py:验证各网络模块的前向形状;
- test_vocoder_losses.py、test_vocoder_pqmf.py、test_vocoder_rwd.py:覆盖损失函数、PQMF 分带与随机窗口判别器;
- test_vocoder_gan_datasets.py:验证 GAN 数据集的切段、padding 与缓存行为。
排查训练问题时,可以对照这些测试确认:配置能否被 setup_model 正确装配(模型/判别器名字拼写错误会在此阶段报 ValueError: Model xxx not exist!)、损失开关组合是否与 test_vocoder_losses.py 中的场景一致、评估样本数是否符合 eval_split_size 预期。
七、小结与致谢
回到 TTS/vocoder/README.md 的原始主张,可以把它浓缩为三条可操作的原则:
- 数据:wav 收进一个目录 →
data_path;需要预计算特征时用feature_path配对 wav 与.npy; - 配置:继承
BaseGANVocoderConfig的 dataclass(或对应的config.json)决定一切——网络结构(*_model+*_model_params)、数据行为(seq_len/pad_short/use_cache)、损失组合(use_*+ 权重)、优化与调度(lr_gen/lr_disc/ ExponentialLR /grad_clip); - 训练:
--config_path新起、--continue_path原地续训、--restore_path换目录只带权重微调,全程 Tensorboard 可观测。
最后按 README 原样保留致谢:本模块的 GAN 声码器工作以 kan-bayashi 的 ParallelWaveGAN 开源实现为起点,仓库在其基础上统一了配置、数据与训练接口。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00