414 lines
16 KiB
Python
414 lines
16 KiB
Python
import copy
|
|
|
|
import numpy as np
|
|
import torch
|
|
import torch.nn as nn
|
|
import torch.nn.functional as F
|
|
from torch import Tensor
|
|
|
|
from deployment.modules.diffusion import (
|
|
GaussianDiffusionONNX, PitchDiffusionONNX, MultiVarianceDiffusionONNX
|
|
)
|
|
from deployment.modules.rectified_flow import (
|
|
RectifiedFlowONNX, PitchRectifiedFlowONNX, MultiVarianceRectifiedFlowONNX
|
|
)
|
|
from deployment.modules.fastspeech2 import FastSpeech2AcousticONNX, FastSpeech2VarianceONNX
|
|
from modules.toplevel import DiffSingerAcoustic, DiffSingerVariance
|
|
from utils.hparams import hparams
|
|
|
|
|
|
class DiffSingerAcousticONNX(DiffSingerAcoustic):
|
|
def __init__(self, vocab_size, out_dims, cross_lingual_token_idx=None):
|
|
super().__init__(vocab_size, out_dims)
|
|
del self.fs2
|
|
del self.diffusion
|
|
self.fs2 = FastSpeech2AcousticONNX(
|
|
vocab_size=vocab_size,
|
|
cross_lingual_token_idx=cross_lingual_token_idx
|
|
)
|
|
if self.diffusion_type == 'ddpm':
|
|
self.diffusion = GaussianDiffusionONNX(
|
|
out_dims=out_dims,
|
|
num_feats=1,
|
|
timesteps=hparams['timesteps'],
|
|
k_step=hparams['K_step'],
|
|
backbone_type=self.backbone_type,
|
|
backbone_args=self.backbone_args,
|
|
spec_min=hparams['spec_min'],
|
|
spec_max=hparams['spec_max']
|
|
)
|
|
elif self.diffusion_type == 'reflow':
|
|
self.diffusion = RectifiedFlowONNX(
|
|
out_dims=out_dims,
|
|
num_feats=1,
|
|
t_start=hparams['T_start'],
|
|
time_scale_factor=hparams['time_scale_factor'],
|
|
backbone_type=self.backbone_type,
|
|
backbone_args=self.backbone_args,
|
|
spec_min=hparams['spec_min'],
|
|
spec_max=hparams['spec_max']
|
|
)
|
|
else:
|
|
raise ValueError(f"Invalid diffusion type: {self.diffusion_type}")
|
|
self.mel_base = hparams.get('mel_base', '10')
|
|
|
|
def ensure_mel_base(self, mel):
|
|
if self.mel_base != 'e':
|
|
# log10 mel to log mel
|
|
mel = mel * 2.30259
|
|
return mel
|
|
|
|
def forward_fs2_aux(
|
|
self,
|
|
tokens: Tensor,
|
|
durations: Tensor,
|
|
f0: Tensor,
|
|
variances: dict,
|
|
gender: Tensor = None,
|
|
velocity: Tensor = None,
|
|
spk_embed: Tensor = None,
|
|
languages: Tensor = None
|
|
):
|
|
condition = self.fs2(
|
|
tokens, durations, f0, variances=variances,
|
|
gender=gender, velocity=velocity, spk_embed=spk_embed,
|
|
languages=languages
|
|
)
|
|
if self.use_shallow_diffusion:
|
|
aux_mel_pred = self.aux_decoder(condition, infer=True)
|
|
return condition, aux_mel_pred
|
|
else:
|
|
return condition
|
|
|
|
def forward_shallow_diffusion(
|
|
self, condition: Tensor, x_start: Tensor,
|
|
depth, steps: int
|
|
) -> Tensor:
|
|
mel_pred = self.diffusion(condition, x_start=x_start, depth=depth, steps=steps)
|
|
return self.ensure_mel_base(mel_pred)
|
|
|
|
def forward_diffusion(self, condition: Tensor, steps: int):
|
|
mel_pred = self.diffusion(condition, steps=steps)
|
|
return self.ensure_mel_base(mel_pred)
|
|
|
|
def forward_shallow_reflow(
|
|
self, condition: Tensor, x_end: Tensor,
|
|
depth, steps: int
|
|
):
|
|
mel_pred = self.diffusion(condition, x_end=x_end, depth=depth, steps=steps)
|
|
return self.ensure_mel_base(mel_pred)
|
|
|
|
def forward_reflow(self, condition: Tensor, steps: int):
|
|
mel_pred = self.diffusion(condition, steps=steps)
|
|
return self.ensure_mel_base(mel_pred)
|
|
|
|
def view_as_fs2_aux(self) -> nn.Module:
|
|
model = copy.deepcopy(self)
|
|
del model.diffusion
|
|
model.forward = model.forward_fs2_aux
|
|
return model
|
|
|
|
def view_as_diffusion(self) -> nn.Module:
|
|
model = copy.deepcopy(self)
|
|
del model.fs2
|
|
if self.use_shallow_diffusion:
|
|
del model.aux_decoder
|
|
model.forward = model.forward_shallow_diffusion
|
|
else:
|
|
model.forward = model.forward_diffusion
|
|
return model
|
|
|
|
def view_as_reflow(self) -> nn.Module:
|
|
model = copy.deepcopy(self)
|
|
del model.fs2
|
|
if self.use_shallow_diffusion:
|
|
del model.aux_decoder
|
|
model.forward = model.forward_shallow_reflow
|
|
else:
|
|
model.forward = model.forward_reflow
|
|
return model
|
|
|
|
|
|
class DiffSingerVarianceONNX(DiffSingerVariance):
|
|
def __init__(self, vocab_size, cross_lingual_token_idx=None):
|
|
super().__init__(vocab_size=vocab_size)
|
|
del self.fs2
|
|
self.fs2 = FastSpeech2VarianceONNX(
|
|
vocab_size=vocab_size,
|
|
cross_lingual_token_idx=cross_lingual_token_idx
|
|
)
|
|
self.hidden_size = hparams['hidden_size']
|
|
if self.predict_pitch:
|
|
del self.pitch_predictor
|
|
self.smooth: nn.Conv1d = None
|
|
pitch_hparams = hparams['pitch_prediction_args']
|
|
if self.diffusion_type == 'ddpm':
|
|
self.pitch_predictor = PitchDiffusionONNX(
|
|
vmin=pitch_hparams['pitd_norm_min'],
|
|
vmax=pitch_hparams['pitd_norm_max'],
|
|
cmin=pitch_hparams['pitd_clip_min'],
|
|
cmax=pitch_hparams['pitd_clip_max'],
|
|
repeat_bins=pitch_hparams['repeat_bins'],
|
|
timesteps=hparams['timesteps'],
|
|
k_step=hparams['K_step'],
|
|
backbone_type=self.pitch_backbone_type,
|
|
backbone_args=self.pitch_backbone_args
|
|
)
|
|
elif self.diffusion_type == 'reflow':
|
|
self.pitch_predictor = PitchRectifiedFlowONNX(
|
|
vmin=pitch_hparams['pitd_norm_min'],
|
|
vmax=pitch_hparams['pitd_norm_max'],
|
|
cmin=pitch_hparams['pitd_clip_min'],
|
|
cmax=pitch_hparams['pitd_clip_max'],
|
|
repeat_bins=pitch_hparams['repeat_bins'],
|
|
time_scale_factor=hparams['time_scale_factor'],
|
|
backbone_type=self.pitch_backbone_type,
|
|
backbone_args=self.pitch_backbone_args
|
|
)
|
|
else:
|
|
raise ValueError(f"Invalid diffusion type: {self.diffusion_type}")
|
|
if self.predict_variances:
|
|
del self.variance_predictor
|
|
if self.diffusion_type == 'ddpm':
|
|
self.variance_predictor = self.build_adaptor(cls=MultiVarianceDiffusionONNX)
|
|
elif self.diffusion_type == 'reflow':
|
|
self.variance_predictor = self.build_adaptor(cls=MultiVarianceRectifiedFlowONNX)
|
|
else:
|
|
raise NotImplementedError(self.diffusion_type)
|
|
|
|
def build_smooth_op(self, device):
|
|
smooth_kernel_size = round(hparams['midi_smooth_width'] * hparams['audio_sample_rate'] / hparams['hop_size'])
|
|
smooth = nn.Conv1d(
|
|
in_channels=1,
|
|
out_channels=1,
|
|
kernel_size=smooth_kernel_size,
|
|
bias=False,
|
|
padding='same',
|
|
padding_mode='replicate'
|
|
).eval()
|
|
smooth_kernel = torch.sin(torch.from_numpy(
|
|
np.linspace(0, 1, smooth_kernel_size).astype(np.float32) * np.pi
|
|
))
|
|
smooth_kernel /= smooth_kernel.sum()
|
|
smooth.weight.data = smooth_kernel[None, None]
|
|
self.smooth = smooth.to(device)
|
|
|
|
def embed_frozen_spk(self, encoder_out):
|
|
if hparams['use_spk_id'] and hasattr(self, 'frozen_spk_embed'):
|
|
encoder_out += self.frozen_spk_embed
|
|
return encoder_out
|
|
|
|
def forward_linguistic_encoder_word(self, tokens, word_div, word_dur, languages=None):
|
|
encoder_out, x_masks = self.fs2.forward_encoder_word(tokens, word_div, word_dur, languages=languages)
|
|
encoder_out = self.embed_frozen_spk(encoder_out)
|
|
return encoder_out, x_masks
|
|
|
|
def forward_linguistic_encoder_phoneme(self, tokens, ph_dur, languages=None):
|
|
encoder_out, x_masks = self.fs2.forward_encoder_phoneme(tokens, ph_dur, languages=languages)
|
|
encoder_out = self.embed_frozen_spk(encoder_out)
|
|
return encoder_out, x_masks
|
|
|
|
def forward_dur_predictor(self, encoder_out, x_masks, ph_midi, spk_embed=None):
|
|
return self.fs2.forward_dur_predictor(encoder_out, x_masks, ph_midi, spk_embed=spk_embed)
|
|
|
|
def forward_mel2x_gather(self, x_src, x_dur, x_dim=None, check_stretch_embed=False):
|
|
mel2x = self.lr(x_dur)
|
|
_mel2x = mel2x
|
|
if x_dim is not None:
|
|
x_src = F.pad(x_src, [0, 0, 1, 0])
|
|
mel2x = mel2x[..., None].repeat([1, 1, x_dim])
|
|
else:
|
|
x_src = F.pad(x_src, [1, 0])
|
|
x_cond = torch.gather(x_src, 1, mel2x)
|
|
if self.use_stretch_embed and check_stretch_embed:
|
|
stretch = torch.round(1000 * self.sr(_mel2x, x_dur))
|
|
table = self.stretch_embed(torch.arange(0, 1001, device=stretch.device))
|
|
stretch_embed = torch.index_select(table, 0, stretch.view(-1).long()).view_as(x_cond)
|
|
x_cond += stretch_embed
|
|
stretch_embed_rnn_out, _ = self.stretch_embed_rnn(x_cond)
|
|
x_cond += stretch_embed_rnn_out
|
|
return x_cond
|
|
|
|
def forward_pitch_preprocess(
|
|
self, encoder_out, ph_dur,
|
|
note_midi=None, note_rest=None, note_dur=None, note_glide=None,
|
|
pitch=None, expr=None, retake=None, spk_embed=None
|
|
):
|
|
condition = self.forward_mel2x_gather(encoder_out, ph_dur, x_dim=self.hidden_size, check_stretch_embed=True)
|
|
if self.use_melody_encoder:
|
|
if self.melody_encoder.use_glide_embed and note_glide is None:
|
|
note_glide = torch.LongTensor([[0]]).to(encoder_out.device)
|
|
melody_encoder_out = self.melody_encoder(
|
|
note_midi, note_rest, note_dur,
|
|
glide=note_glide
|
|
)
|
|
melody_encoder_out = self.forward_mel2x_gather(melody_encoder_out, note_dur, x_dim=self.hidden_size)
|
|
condition += melody_encoder_out
|
|
if expr is None:
|
|
retake_embed = self.pitch_retake_embed(retake.long())
|
|
else:
|
|
retake_true_embed = self.pitch_retake_embed(
|
|
torch.ones(1, 1, dtype=torch.long, device=encoder_out.device)
|
|
) # [B=1, T=1] => [B=1, T=1, H]
|
|
retake_false_embed = self.pitch_retake_embed(
|
|
torch.zeros(1, 1, dtype=torch.long, device=encoder_out.device)
|
|
) # [B=1, T=1] => [B=1, T=1, H]
|
|
expr = (expr * retake)[:, :, None] # [B, T, 1]
|
|
retake_embed = expr * retake_true_embed + (1. - expr) * retake_false_embed
|
|
pitch_cond = condition + retake_embed
|
|
frame_midi_pitch = self.forward_mel2x_gather(note_midi, note_dur, x_dim=None)
|
|
base_pitch = self.smooth(frame_midi_pitch)
|
|
if self.use_melody_encoder:
|
|
delta_pitch = (pitch - base_pitch) * ~retake
|
|
if self.use_variance_scaling:
|
|
pitch_cond += self.delta_pitch_embed(delta_pitch[:, :, None] / 12)
|
|
else:
|
|
pitch_cond += self.delta_pitch_embed(delta_pitch[:, :, None])
|
|
else:
|
|
base_pitch = base_pitch * retake + pitch * ~retake
|
|
if self.use_variance_scaling:
|
|
pitch_cond += self.base_pitch_embed(base_pitch[:, :, None] / 128)
|
|
else:
|
|
pitch_cond += self.base_pitch_embed(base_pitch[:, :, None])
|
|
if hparams['use_spk_id'] and spk_embed is not None:
|
|
pitch_cond += spk_embed
|
|
return pitch_cond, base_pitch
|
|
|
|
def forward_pitch_reflow(
|
|
self, pitch_cond, steps: int = 10
|
|
):
|
|
x_pred = self.pitch_predictor(pitch_cond, steps=steps)
|
|
return x_pred
|
|
|
|
def forward_pitch_postprocess(self, x_pred, base_pitch):
|
|
pitch_pred = self.pitch_predictor.clamp_spec(x_pred) + base_pitch
|
|
return pitch_pred
|
|
|
|
def forward_variance_preprocess(
|
|
self, encoder_out, ph_dur, pitch,
|
|
variances: dict = None, retake=None, spk_embed=None
|
|
):
|
|
condition = self.forward_mel2x_gather(encoder_out, ph_dur, x_dim=self.hidden_size, check_stretch_embed=True)
|
|
if self.use_variance_scaling:
|
|
variance_cond = condition + self.pitch_embed(pitch[:, :, None] / 12)
|
|
else:
|
|
variance_cond = condition + self.pitch_embed(pitch[:, :, None])
|
|
non_retake_masks = [
|
|
v_retake.float() # [B, T, 1]
|
|
for v_retake in (~retake).split(1, dim=2)
|
|
]
|
|
variance_embeds = [
|
|
self.variance_embeds[v_name](variances[v_name][:, :, None] * self.variance_retake_scaling[v_name]) * v_masks
|
|
for v_name, v_masks in zip(self.variance_prediction_list, non_retake_masks)
|
|
]
|
|
variance_cond += torch.stack(variance_embeds, dim=-1).sum(-1)
|
|
if hparams['use_spk_id'] and spk_embed is not None:
|
|
variance_cond += spk_embed
|
|
return variance_cond
|
|
|
|
def forward_variance_reflow(self, variance_cond, steps: int = 10):
|
|
xs_pred = self.variance_predictor(variance_cond, steps=steps)
|
|
return xs_pred
|
|
|
|
def forward_variance_postprocess(self, xs_pred):
|
|
if self.variance_predictor.num_feats == 1:
|
|
xs_pred = [xs_pred]
|
|
else:
|
|
xs_pred = xs_pred.unbind(dim=1)
|
|
variance_pred = self.variance_predictor.clamp_spec(xs_pred)
|
|
return tuple(variance_pred)
|
|
|
|
def view_as_linguistic_encoder(self):
|
|
model = copy.deepcopy(self)
|
|
if self.predict_pitch:
|
|
del model.pitch_predictor
|
|
if self.use_melody_encoder:
|
|
del model.melody_encoder
|
|
if self.predict_variances:
|
|
del model.variance_predictor
|
|
model.fs2 = model.fs2.view_as_encoder()
|
|
if self.predict_dur:
|
|
model.forward = model.forward_linguistic_encoder_word
|
|
else:
|
|
model.forward = model.forward_linguistic_encoder_phoneme
|
|
return model
|
|
|
|
def view_as_dur_predictor(self):
|
|
assert self.predict_dur
|
|
model = copy.deepcopy(self)
|
|
if self.predict_pitch:
|
|
del model.pitch_predictor
|
|
if self.use_melody_encoder:
|
|
del model.melody_encoder
|
|
if self.predict_variances:
|
|
del model.variance_predictor
|
|
model.fs2 = model.fs2.view_as_dur_predictor()
|
|
model.forward = model.forward_dur_predictor
|
|
return model
|
|
|
|
def view_as_pitch_preprocess(self):
|
|
model = copy.deepcopy(self)
|
|
del model.fs2
|
|
if self.predict_pitch:
|
|
del model.pitch_predictor
|
|
if self.predict_variances:
|
|
del model.variance_predictor
|
|
model.forward = model.forward_pitch_preprocess
|
|
return model
|
|
|
|
def view_as_pitch_predictor(self):
|
|
assert self.predict_pitch
|
|
model = copy.deepcopy(self)
|
|
del model.fs2
|
|
del model.lr
|
|
if self.use_melody_encoder:
|
|
del model.melody_encoder
|
|
if self.predict_variances:
|
|
del model.variance_predictor
|
|
model.forward = model.forward_pitch_reflow
|
|
return model
|
|
|
|
def view_as_pitch_postprocess(self):
|
|
model = copy.deepcopy(self)
|
|
del model.fs2
|
|
if self.use_melody_encoder:
|
|
del model.melody_encoder
|
|
if self.predict_variances:
|
|
del model.variance_predictor
|
|
model.forward = model.forward_pitch_postprocess
|
|
return model
|
|
|
|
def view_as_variance_preprocess(self):
|
|
model = copy.deepcopy(self)
|
|
del model.fs2
|
|
if self.predict_pitch:
|
|
del model.pitch_predictor
|
|
if self.use_melody_encoder:
|
|
del model.melody_encoder
|
|
if self.predict_variances:
|
|
del model.variance_predictor
|
|
model.forward = model.forward_variance_preprocess
|
|
return model
|
|
|
|
def view_as_variance_predictor(self):
|
|
assert self.predict_variances
|
|
model = copy.deepcopy(self)
|
|
del model.fs2
|
|
del model.lr
|
|
if self.predict_pitch:
|
|
del model.pitch_predictor
|
|
if self.use_melody_encoder:
|
|
del model.melody_encoder
|
|
model.forward = model.forward_variance_reflow
|
|
return model
|
|
|
|
def view_as_variance_postprocess(self):
|
|
model = copy.deepcopy(self)
|
|
del model.fs2
|
|
if self.predict_pitch:
|
|
del model.pitch_predictor
|
|
if self.use_melody_encoder:
|
|
del model.melody_encoder
|
|
model.forward = model.forward_variance_postprocess
|
|
return model
|