AUTOVC 代码解析 —— synthesis.py
简介
本项目一个基于 AUTOVC 模型的语音转换项目,它是使用 PyTorch 实现的(项目地址)。
AUTOVC 遵循自动编码器框架,只对自动编码器损耗进行训练,但它引入了精心调整的降维和时间下采样来约束信息流,这个简单的方案带来了显著的性能提高。(详情请参阅 AUTOVC 的详细介绍)。
由于 AUTOVC 项目较大,代码较多。为了方便学习与整理,将按照工程文件的结构依次介绍。
本文将介绍项目中的 synthesis.py 文件:转换后梅尔数据语音生成脚本。
函数解析
build_model
该函数的作用是: 创建一个 WaveNet 模型
输入参数: 无
输出参数:
model : 生成的 WaveNet 模型
代码详解:
def build_model():
# builder 来自 wavenet_vocoder.builder , hparams.builder 为 'wavenet'
# 故 getattr(builder, hparams.builder) 是在获取 getattr(builder, hparams.builder).wavenet
model = getattr(builder, hparams.builder)(
# 输出通道数为 30
out_channels=hparams.out_channels,
# 层数为 24
layers=hparams.layers,
# 膨胀循环的次数为 4
stacks=hparams.stacks,
# 残差输入输出通道数为 512
residual_channels=hparams.residual_channels,
# 门控激活通道数为 512
gate_channels=hparams.gate_channels,
# 跳步连接通道数为 256
skip_out_channels=hparams.skip_out_channels,
# 本地条件通道为 80
cin_channels=hparams.cin_channels,
# 全局条件通道为 -1 (禁用)
gin_channels=hparams.gin_channels,
# 权重规范化标志为 True ,使用转置卷积对条件特征进行上采样
weight_normalization=hparams.weight_normalization,
# 说话人的数量为 -1 ,仅在全局条件作用下使用启用
n_speakers=hparams.n_speakers,
# Dropout 比例为 0.05
dropout=hparams.dropout,
# 卷积层的核大小为 3
kernel_size=hparams.kernel_size,
# 是否通过转置卷积层对局部条件作用特征进行上采样为 True
upsample_conditional_features=hparams.upsample_conditional_features,
# 上采样规模的列表, np.prod(upsample_scales) 必须等于跳数大小,仅当 upsample_conditional_features 已启用时使用
upsample_scales=hparams.upsample_scales,
# 用于上采样的转置卷积层的频率轴内核大小为 3 (如果只关心时间轴上采样,则将其设置为1)
freq_axis_kernel_size=hparams.freq_axis_kernel_size,
# 期望标量输入([- 1,1])
scalar_input=True,
# 是否使用遗留代码为 True (因为我们已经提供了一个基于遗留代码的模型,可以生成高质量的音频)
legacy=hparams.legacy,
)
# 将上述组装的 WaveNet 模型返回
return model
build_model
该函数的作用是: 利用 WaveNet 模型生成波形样本
输入参数:
model : WaveNet 模型
c : 转换后语音--梅尔数据
tqdm : 进度条
输出参数:
y_hat : 生成的语音波形
代码详解:
def wavegen(model, c=None, tqdm=tqdm):
# 将 WaveNet 模型设置为生成模式
model.eval()
# 从模块中移除权重规范化重新参数化
model.make_generation_fast_()
# 取转换后语音梅尔数据长度
Tc = c.shape[0]
# 取采样跳步大小
upsample_factor = hparams.hop_size
# 根据特征大小修正长度
length = Tc * upsample_factor
# B x C x T
# 将转换后语音梅尔数据转置后转换为 Tensor ,在维度 0 增加新的维度
c = torch.FloatTensor(c.T).unsqueeze(0)
# 初始化输入 Tensor
initial_input = torch.zeros(1, 1, 1).fill_(0.0)
# 将数据转换到 GPU 设备
initial_input = initial_input.to(device)
# 若 c 存在,则将数据转换到 GPU 设备
c = None if c is None else c.to(device)
# torch.no_grad 是一个上下文管理器,被该语句 wrap 起来的部分将不会 track 梯度
with torch.no_grad():
# 生成音频波形
y_hat = model.incremental_forward(
initial_input, c=c, g=None, T=length, tqdm=tqdm, softmax=True, quantize=True,
log_scale_min=hparams.log_scale_min)
# 将音频波形数据平铺,转换到 cpu 设备,并转换为 numpy 数组
y_hat = y_hat.view(-1).cpu().data.numpy()
# 返回音频波形数据
return y_hat