STAR / models /content_encoder /midi_encoder.py
Yixuan Li
first commit
4853fdc
Raw
History Blame Contribute Delete
35.4 kB
from typing import Sequence
from dataclasses import dataclass
import math
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.nn import Parameter
from utils.torch_utilities import create_mask_from_length
from utils.diffsinger_utilities import denorm_f0, f0_to_coarse
def make_positions(tensor, padding_idx):
"""Replace non-padding symbols with their position numbers.
Position numbers begin at padding_idx+1. Padding symbols are ignored.
"""
# The series of casts and type-conversions here are carefully
# balanced to both work with ONNX export and XLA. In particular XLA
# prefers ints, cumsum defaults to output longs, and ONNX doesn't know
# how to handle the dtype kwarg in cumsum.
mask = tensor.ne(padding_idx).int()
return (torch.cumsum(mask, dim=1).type_as(mask) *
mask).long() + padding_idx
def softmax(x, dim):
return F.softmax(x, dim=dim, dtype=torch.float32)
def LayerNorm(
normalized_shape, eps=1e-5, elementwise_affine=True, export=False
):
if not export and torch.cuda.is_available():
try:
from apex.normalization import FusedLayerNorm
return FusedLayerNorm(normalized_shape, eps, elementwise_affine)
except ImportError:
pass
return torch.nn.LayerNorm(normalized_shape, eps, elementwise_affine)
def Linear(in_features, out_features, bias=True):
m = nn.Linear(in_features, out_features, bias)
nn.init.xavier_uniform_(m.weight)
if bias:
nn.init.constant_(m.bias, 0.)
return m
def Embedding(num_embeddings, embedding_dim, padding_idx=None):
m = nn.Embedding(num_embeddings, embedding_dim, padding_idx=padding_idx)
nn.init.normal_(m.weight, mean=0, std=embedding_dim**-0.5)
if padding_idx is not None:
nn.init.constant_(m.weight[padding_idx], 0)
return m
class BatchNorm1dTBC(nn.Module):
def __init__(self, c):
super(BatchNorm1dTBC, self).__init__()
self.bn = nn.BatchNorm1d(c)
def forward(self, x):
"""
:param x: [T, B, C]
:return: [T, B, C]
"""
x = x.permute(1, 2, 0) # [B, C, T]
x = self.bn(x) # [B, C, T]
x = x.permute(2, 0, 1) # [T, B, C]
return x
class PositionalEncoding(nn.Module):
"""Positional encoding.
Args:
d_model (int): Embedding dimension.
dropout_rate (float): Dropout rate.
max_len (int): Maximum input length.
reverse (bool): Whether to reverse the input position.
"""
def __init__(self, d_model, dropout_rate, max_len=5000, reverse=False):
"""Construct an PositionalEncoding object."""
super(PositionalEncoding, self).__init__()
self.d_model = d_model
self.reverse = reverse
self.xscale = math.sqrt(self.d_model)
self.dropout = torch.nn.Dropout(p=dropout_rate)
self.pe = None
self.extend_pe(torch.tensor(0.0).expand(1, max_len))
def extend_pe(self, x):
"""Reset the positional encodings."""
if self.pe is not None:
if self.pe.size(1) >= x.size(1):
if self.pe.dtype != x.dtype or self.pe.device != x.device:
self.pe = self.pe.to(dtype=x.dtype, device=x.device)
return
pe = torch.zeros(x.size(1), self.d_model)
if self.reverse:
position = torch.arange(
x.size(1) - 1, -1, -1.0, dtype=torch.float32
).unsqueeze(1)
else:
position = torch.arange(0, x.size(1),
dtype=torch.float32).unsqueeze(1)
div_term = torch.exp(
torch.arange(0, self.d_model, 2, dtype=torch.float32) *
-(math.log(10000.0) / self.d_model)
)
pe[:, 0::2] = torch.sin(position * div_term)
pe[:, 1::2] = torch.cos(position * div_term)
pe = pe.unsqueeze(0)
self.pe = pe.to(device=x.device, dtype=x.dtype)
def forward(self, x: torch.Tensor):
"""Add positional encoding.
Args:
x (torch.Tensor): Input tensor (batch, time, `*`).
Returns:
torch.Tensor: Encoded tensor (batch, time, `*`).
"""
self.extend_pe(x)
x = x * self.xscale + self.pe[:, :x.size(1)]
return self.dropout(x)
class SinusoidalPositionalEmbedding(nn.Module):
"""This module produces sinusoidal positional embeddings of any length.
Padding symbols are ignored.
"""
def __init__(self, d_model, padding_idx, init_size=2048):
super().__init__()
self.d_model = d_model
self.padding_idx = padding_idx
self.weights = SinusoidalPositionalEmbedding.get_embedding(
init_size,
d_model,
padding_idx,
)
self.register_buffer('_float_tensor', torch.FloatTensor(1))
@staticmethod
def get_embedding(num_embeddings, d_model, padding_idx=None):
"""Build sinusoidal embeddings.
This matches the implementation in tensor2tensor, but differs slightly
from the description in Section 3.5 of "Attention Is All You Need".
"""
half_dim = d_model // 2
emb = math.log(10000) / (half_dim - 1)
emb = torch.exp(torch.arange(half_dim, dtype=torch.float) * -emb)
emb = torch.arange(num_embeddings,
dtype=torch.float).unsqueeze(1) * emb.unsqueeze(0)
emb = torch.cat([torch.sin(emb), torch.cos(emb)],
dim=1).view(num_embeddings, -1)
if d_model % 2 == 1:
# zero pad
emb = torch.cat([emb, torch.zeros(num_embeddings, 1)], dim=1)
if padding_idx is not None:
emb[padding_idx, :] = 0
return emb
def forward(
self,
x,
lengths,
incremental_state=None,
timestep=None,
positions=None,
**kwargs
):
"""Input is expected to be of size [bsz x seqlen]."""
bsz, seq_len = x.shape[:2]
max_pos = self.padding_idx + 1 + seq_len
if self.weights is None or max_pos > self.weights.size(0):
# recompute/expand embeddings if needed
self.weights = SinusoidalPositionalEmbedding.get_embedding(
max_pos,
self.d_model,
self.padding_idx,
)
self.weights = self.weights.to(self._float_tensor)
if incremental_state is not None:
# positions is the same for every token when decoding a single step
pos = timestep.view(-1)[0] + 1 if timestep is not None else seq_len
return self.weights[self.padding_idx + pos, :].expand(bsz, 1, -1)
positions = create_mask_from_length(
lengths, max_length=x.shape[1]
) * (torch.arange(x.shape[1]) + 1).unsqueeze(0).expand(x.shape[0], -1)
positions = positions.to(self.weights.device)
pos_emb = self.weights.index_select(0, positions.view(-1)).view(
bsz, seq_len, -1
).detach()
return x + pos_emb
def max_positions(self):
"""Maximum number of supported positions."""
return int(1e5) # an arbitrary large number
class RelPositionalEncoding(PositionalEncoding):
"""Relative positional encoding module.
See : Appendix B in https://arxiv.org/abs/1901.02860
Args:
d_model (int): Embedding dimension.
dropout_rate (float): Dropout rate.
max_len (int): Maximum input length.
"""
def __init__(self, d_model, dropout_rate, max_len=5000):
"""Initialize class."""
super().__init__(d_model, dropout_rate, max_len, reverse=True)
def forward(self, x, lengths):
"""Compute positional encoding.
Args:
x (torch.Tensor): Input tensor (batch, time, `*`).
Returns:
torch.Tensor: Encoded tensor (batch, time, `*`).
torch.Tensor: Positional embedding tensor (1, time, `*`).
"""
self.extend_pe(x)
x = x * self.xscale
pos_emb = self.pe[:, :x.size(1)]
return self.dropout(x) + self.dropout(pos_emb)
class MultiheadAttention(nn.Module):
def __init__(
self,
embed_dim,
num_heads,
kdim=None,
vdim=None,
dropout=0.,
bias=True,
add_bias_kv=False,
add_zero_attn=False,
self_attention=False,
encoder_decoder_attention=False
):
super().__init__()
self.embed_dim = embed_dim
self.kdim = kdim if kdim is not None else embed_dim
self.vdim = vdim if vdim is not None else embed_dim
self.qkv_same_dim = self.kdim == embed_dim and self.vdim == embed_dim
self.num_heads = num_heads
self.dropout = dropout
self.head_dim = embed_dim // num_heads
assert self.head_dim * num_heads == self.embed_dim, "embed_dim must be divisible by num_heads"
self.scaling = self.head_dim**-0.5
self.self_attention = self_attention
self.encoder_decoder_attention = encoder_decoder_attention
assert not self.self_attention or self.qkv_same_dim, 'Self-attention requires query, key and ' \
'value to be of the same size'
if self.qkv_same_dim:
self.in_proj_weight = Parameter(
torch.Tensor(3 * embed_dim, embed_dim)
)
else:
self.k_proj_weight = Parameter(torch.Tensor(embed_dim, self.kdim))
self.v_proj_weight = Parameter(torch.Tensor(embed_dim, self.vdim))
self.q_proj_weight = Parameter(torch.Tensor(embed_dim, embed_dim))
if bias:
self.in_proj_bias = Parameter(torch.Tensor(3 * embed_dim))
else:
self.register_parameter('in_proj_bias', None)
self.out_proj = nn.Linear(embed_dim, embed_dim, bias=bias)
if add_bias_kv:
self.bias_k = Parameter(torch.Tensor(1, 1, embed_dim))
self.bias_v = Parameter(torch.Tensor(1, 1, embed_dim))
else:
self.bias_k = self.bias_v = None
self.add_zero_attn = add_zero_attn
self.reset_parameters()
self.enable_torch_version = False
if hasattr(F, "multi_head_attention_forward"):
self.enable_torch_version = True
else:
self.enable_torch_version = False
self.last_attn_probs = None
def reset_parameters(self):
if self.qkv_same_dim:
nn.init.xavier_uniform_(self.in_proj_weight)
else:
nn.init.xavier_uniform_(self.k_proj_weight)
nn.init.xavier_uniform_(self.v_proj_weight)
nn.init.xavier_uniform_(self.q_proj_weight)
nn.init.xavier_uniform_(self.out_proj.weight)
if self.in_proj_bias is not None:
nn.init.constant_(self.in_proj_bias, 0.)
nn.init.constant_(self.out_proj.bias, 0.)
if self.bias_k is not None:
nn.init.xavier_normal_(self.bias_k)
if self.bias_v is not None:
nn.init.xavier_normal_(self.bias_v)
def forward(
self,
query,
key,
value,
key_padding_mask=None,
incremental_state=None,
need_weights=True,
static_kv=False,
attn_mask=None,
before_softmax=False,
need_head_weights=False,
enc_dec_attn_constraint_mask=None,
reset_attn_weight=None
):
"""Input shape: Time x Batch x Channel
Args:
key_padding_mask (ByteTensor, optional): mask to exclude
keys that are pads, of shape `(batch, src_len)`, where
padding elements are indicated by 1s.
need_weights (bool, optional): return the attention weights,
averaged over heads (default: False).
attn_mask (ByteTensor, optional): typically used to
implement causal attention, where the mask prevents the
attention from looking forward in time (default: None).
before_softmax (bool, optional): return the raw attention
weights and values before the attention softmax.
need_head_weights (bool, optional): return the attention
weights for each head. Implies *need_weights*. Default:
return the average attention weights over all heads.
"""
if need_head_weights:
need_weights = True
tgt_len, bsz, embed_dim = query.size()
assert embed_dim == self.embed_dim
assert list(query.size()) == [tgt_len, bsz, embed_dim]
if self.enable_torch_version and incremental_state is None and not static_kv and reset_attn_weight is None:
if self.qkv_same_dim:
return F.multi_head_attention_forward(
query, key, value, self.embed_dim, self.num_heads,
self.in_proj_weight, self.in_proj_bias, self.bias_k,
self.bias_v, self.add_zero_attn, self.dropout,
self.out_proj.weight, self.out_proj.bias, self.training,
key_padding_mask, need_weights, attn_mask
)
else:
return F.multi_head_attention_forward(
query,
key,
value,
self.embed_dim,
self.num_heads,
torch.empty([0]),
self.in_proj_bias,
self.bias_k,
self.bias_v,
self.add_zero_attn,
self.dropout,
self.out_proj.weight,
self.out_proj.bias,
self.training,
key_padding_mask,
need_weights,
attn_mask,
use_separate_proj_weight=True,
q_proj_weight=self.q_proj_weight,
k_proj_weight=self.k_proj_weight,
v_proj_weight=self.v_proj_weight
)
if incremental_state is not None:
print('Not implemented error.')
exit()
else:
saved_state = None
if self.self_attention:
# self-attention
q, k, v = self.in_proj_qkv(query)
elif self.encoder_decoder_attention:
# encoder-decoder attention
q = self.in_proj_q(query)
if key is None:
assert value is None
k = v = None
else:
k = self.in_proj_k(key)
v = self.in_proj_v(key)
else:
q = self.in_proj_q(query)
k = self.in_proj_k(key)
v = self.in_proj_v(value)
q *= self.scaling
if self.bias_k is not None:
assert self.bias_v is not None
k = torch.cat([k, self.bias_k.repeat(1, bsz, 1)])
v = torch.cat([v, self.bias_v.repeat(1, bsz, 1)])
if attn_mask is not None:
attn_mask = torch.cat(
[attn_mask,
attn_mask.new_zeros(attn_mask.size(0), 1)],
dim=1
)
if key_padding_mask is not None:
key_padding_mask = torch.cat(
[
key_padding_mask,
key_padding_mask.new_zeros(
key_padding_mask.size(0), 1
)
],
dim=1
)
q = q.contiguous().view(tgt_len, bsz * self.num_heads,
self.head_dim).transpose(0, 1)
if k is not None:
k = k.contiguous().view(-1, bsz * self.num_heads,
self.head_dim).transpose(0, 1)
if v is not None:
v = v.contiguous().view(-1, bsz * self.num_heads,
self.head_dim).transpose(0, 1)
if saved_state is not None:
print('Not implemented error.')
exit()
src_len = k.size(1)
# This is part of a workaround to get around fork/join parallelism
# not supporting Optional types.
if key_padding_mask is not None and key_padding_mask.shape == torch.Size(
[]
):
key_padding_mask = None
if key_padding_mask is not None:
assert key_padding_mask.size(0) == bsz
assert key_padding_mask.size(1) == src_len
if self.add_zero_attn:
src_len += 1
k = torch.cat(
[k, k.new_zeros((k.size(0), 1) + k.size()[2:])], dim=1
)
v = torch.cat(
[v, v.new_zeros((v.size(0), 1) + v.size()[2:])], dim=1
)
if attn_mask is not None:
attn_mask = torch.cat(
[attn_mask,
attn_mask.new_zeros(attn_mask.size(0), 1)],
dim=1
)
if key_padding_mask is not None:
key_padding_mask = torch.cat(
[
key_padding_mask,
torch.zeros(key_padding_mask.size(0),
1).type_as(key_padding_mask)
],
dim=1
)
attn_weights = torch.bmm(q, k.transpose(1, 2))
attn_weights = self.apply_sparse_mask(
attn_weights, tgt_len, src_len, bsz
)
assert list(attn_weights.size()) == [
bsz * self.num_heads, tgt_len, src_len
]
if attn_mask is not None:
if len(attn_mask.shape) == 2:
attn_mask = attn_mask.unsqueeze(0)
elif len(attn_mask.shape) == 3:
attn_mask = attn_mask[:, None].repeat(
[1, self.num_heads, 1, 1]
).reshape(bsz * self.num_heads, tgt_len, src_len)
attn_weights = attn_weights + attn_mask
if enc_dec_attn_constraint_mask is not None: # bs x head x L_kv
attn_weights = attn_weights.view(
bsz, self.num_heads, tgt_len, src_len
)
attn_weights = attn_weights.masked_fill(
enc_dec_attn_constraint_mask.unsqueeze(2).bool(),
-1e9,
)
attn_weights = attn_weights.view(
bsz * self.num_heads, tgt_len, src_len
)
if key_padding_mask is not None:
# don't attend to padding symbols
attn_weights = attn_weights.view(
bsz, self.num_heads, tgt_len, src_len
)
attn_weights = attn_weights.masked_fill(
key_padding_mask.unsqueeze(1).unsqueeze(2),
-1e9,
)
attn_weights = attn_weights.view(
bsz * self.num_heads, tgt_len, src_len
)
attn_logits = attn_weights.view(bsz, self.num_heads, tgt_len, src_len)
if before_softmax:
return attn_weights, v
attn_weights_float = softmax(attn_weights, dim=-1)
attn_weights = attn_weights_float.type_as(attn_weights)
attn_probs = F.dropout(
attn_weights_float.type_as(attn_weights),
p=self.dropout,
training=self.training
)
if reset_attn_weight is not None:
if reset_attn_weight:
self.last_attn_probs = attn_probs.detach()
else:
assert self.last_attn_probs is not None
attn_probs = self.last_attn_probs
attn = torch.bmm(attn_probs, v)
assert list(attn.size()) == [
bsz * self.num_heads, tgt_len, self.head_dim
]
attn = attn.transpose(0, 1).contiguous().view(tgt_len, bsz, embed_dim)
attn = self.out_proj(attn)
if need_weights:
attn_weights = attn_weights_float.view(
bsz, self.num_heads, tgt_len, src_len
).transpose(1, 0)
if not need_head_weights:
# average attention weights over heads
attn_weights = attn_weights.mean(dim=0)
else:
attn_weights = None
return attn, (attn_weights, attn_logits)
def in_proj_qkv(self, query):
return self._in_proj(query).chunk(3, dim=-1)
def in_proj_q(self, query):
if self.qkv_same_dim:
return self._in_proj(query, end=self.embed_dim)
else:
bias = self.in_proj_bias
if bias is not None:
bias = bias[:self.embed_dim]
return F.linear(query, self.q_proj_weight, bias)
def in_proj_k(self, key):
if self.qkv_same_dim:
return self._in_proj(
key, start=self.embed_dim, end=2 * self.embed_dim
)
else:
weight = self.k_proj_weight
bias = self.in_proj_bias
if bias is not None:
bias = bias[self.embed_dim:2 * self.embed_dim]
return F.linear(key, weight, bias)
def in_proj_v(self, value):
if self.qkv_same_dim:
return self._in_proj(value, start=2 * self.embed_dim)
else:
weight = self.v_proj_weight
bias = self.in_proj_bias
if bias is not None:
bias = bias[2 * self.embed_dim:]
return F.linear(value, weight, bias)
def _in_proj(self, input, start=0, end=None):
weight = self.in_proj_weight
bias = self.in_proj_bias
weight = weight[start:end, :]
if bias is not None:
bias = bias[start:end]
return F.linear(input, weight, bias)
def apply_sparse_mask(self, attn_weights, tgt_len, src_len, bsz):
return attn_weights
class TransformerFFNLayer(nn.Module):
def __init__(
self,
hidden_size,
filter_size,
padding="SAME",
kernel_size=1,
dropout=0.,
act='gelu'
):
super().__init__()
self.kernel_size = kernel_size
self.dropout = dropout
self.act = act
if padding == 'SAME':
self.ffn_1 = nn.Conv1d(
hidden_size,
filter_size,
kernel_size,
padding=kernel_size // 2
)
elif padding == 'LEFT':
self.ffn_1 = nn.Sequential(
nn.ConstantPad1d((kernel_size - 1, 0), 0.0),
nn.Conv1d(hidden_size, filter_size, kernel_size)
)
self.ffn_2 = nn.Linear(filter_size, hidden_size)
def forward(
self,
x,
):
# x: T x B x C
x = self.ffn_1(x.permute(1, 2, 0)).permute(2, 0, 1)
x = x * self.kernel_size**-0.5
if self.act == 'gelu':
x = F.gelu(x)
if self.act == 'relu':
x = F.relu(x)
if self.act == 'swish':
x = F.silu(x)
x = F.dropout(x, self.dropout, training=self.training)
x = self.ffn_2(x)
return x
class EncoderSelfAttentionLayer(nn.Module):
def __init__(
self,
c,
num_heads,
dropout,
attention_dropout=0.1,
relu_dropout=0.1,
kernel_size=9,
padding='SAME',
norm='ln',
act='gelu',
padding_set_zero=True
):
super().__init__()
self.c = c
self.dropout = dropout
self.num_heads = num_heads
self.padding_set_zero = padding_set_zero
if num_heads > 0:
if norm == 'ln':
self.layer_norm1 = LayerNorm(c)
elif norm == 'bn':
self.layer_norm1 = BatchNorm1dTBC(c)
self.self_attn = MultiheadAttention(
self.c,
num_heads=num_heads,
self_attention=True,
dropout=attention_dropout,
bias=False,
)
if norm == 'ln':
self.layer_norm2 = LayerNorm(c)
elif norm == 'bn':
self.layer_norm2 = BatchNorm1dTBC(c)
self.ffn = TransformerFFNLayer(
c,
4 * c,
kernel_size=kernel_size,
dropout=relu_dropout,
padding=padding,
act=act
)
def forward(self, x, encoder_padding_mask=None, **kwargs):
layer_norm_training = kwargs.get('layer_norm_training', None)
if layer_norm_training is not None:
self.layer_norm1.training = layer_norm_training
self.layer_norm2.training = layer_norm_training
if self.num_heads > 0:
residual = x
x = self.layer_norm1(x)
x, _, = self.self_attn(
query=x, key=x, value=x, key_padding_mask=encoder_padding_mask
)
x = F.dropout(x, self.dropout, training=self.training)
x = residual + x
if self.padding_set_zero:
x = x * (1 - encoder_padding_mask.float()).transpose(0,
1)[...,
None]
residual = x
x = self.layer_norm2(x)
x = self.ffn(x)
x = F.dropout(x, self.dropout, training=self.training)
x = residual + x
if self.padding_set_zero:
x = x * (1 - encoder_padding_mask.float()).transpose(0, 1)[...,
None]
return x
class TransformerEncoderLayer(nn.Module):
def __init__(
self,
hidden_size,
dropout,
kernel_size,
num_heads=2,
norm='ln',
padding_set_zero=True,
):
super().__init__()
self.hidden_size = hidden_size
self.dropout = dropout
self.num_heads = num_heads
self.op = EncoderSelfAttentionLayer(
hidden_size,
num_heads,
dropout=dropout,
attention_dropout=0.0,
relu_dropout=dropout,
kernel_size=kernel_size,
padding="SAME",
norm=norm,
act="gelu",
padding_set_zero=padding_set_zero
)
def forward(self, x, **kwargs):
return self.op(x, **kwargs)
class FFTBlocks(nn.Module):
def __init__(
self,
hidden_size,
num_layers,
ffn_kernel_size=9,
dropout=0.1,
num_heads=2,
use_last_norm=True,
padding_set_zero=True,
):
super().__init__()
self.num_layers = num_layers
embed_dim = self.hidden_size = hidden_size
self.dropout = dropout
self.use_last_norm = use_last_norm
self.padding_set_zero = padding_set_zero
self.layers = nn.ModuleList([])
self.layers.extend(
[
TransformerEncoderLayer(
self.hidden_size,
self.dropout,
kernel_size=ffn_kernel_size,
num_heads=num_heads,
padding_set_zero=padding_set_zero,
) for _ in range(self.num_layers)
]
)
if self.use_last_norm:
self.layer_norm = nn.LayerNorm(embed_dim)
else:
self.layer_norm = None
def forward(self, x, padding_mask=None, attn_mask=None):
"""
:param x: [B, T, C]
:param padding_mask: [B, T]
:return: [B, T, C] or [L, B, T, C]
"""
if padding_mask is None:
padding_mask = torch.zeros(x.size(0), x.size(1)).to(x.device)
nonpadding_mask_TB = 1 - padding_mask.transpose(0, 1).float(
)[:, :, None] # [T, B, 1]
# B x T x C -> T x B x C
x = x.transpose(0, 1)
if self.padding_set_zero:
x = x * nonpadding_mask_TB
for layer in self.layers:
x = layer(
x, encoder_padding_mask=padding_mask, attn_mask=attn_mask
)
if self.padding_set_zero:
x = x * nonpadding_mask_TB
if self.use_last_norm:
x = self.layer_norm(x)
if self.padding_set_zero:
x = x * nonpadding_mask_TB
x = x.transpose(0, 1) # [B, T, C]
return x
class FastSpeech2EncoderBase(nn.Module):
def __init__(
self,
d_model: int,
num_layers: int,
num_heads: int,
ffn_kernel_size: int,
d_out: int,
dropout: float = 0.1,
rel_pos: bool = True,
padding_set_zero: bool = True
):
super().__init__()
self.rel_pos = rel_pos
if self.rel_pos:
self.pos_encoding = RelPositionalEncoding(
d_model, dropout_rate=0.0
)
else:
self.pos_encoding = SinusoidalPositionalEmbedding(
d_model, padding_idx=0
)
self.dropout = dropout
self.embed_scale = math.sqrt(d_model)
self.layers = FFTBlocks(
hidden_size=d_model,
num_layers=num_layers,
ffn_kernel_size=ffn_kernel_size,
dropout=dropout,
num_heads=num_heads,
use_last_norm=True,
padding_set_zero=padding_set_zero
)
self.out_proj = nn.Linear(d_model, d_out)
self.apply(self.init_weights)
def init_weights(self, m):
if isinstance(m, nn.Linear):
nn.init.xavier_uniform_(m.weight)
if m.bias is not None:
nn.init.constant_(m.bias, 0.)
elif isinstance(m, nn.Embedding):
nn.init.normal_(m.weight, mean=0, std=m.embedding_dim**-0.5)
@dataclass
class SpkConfig:
encoding_format: str
num_spk: int | None = None
spk_embed_dim: int | None = None
def __post_init__(self):
allowed_formats = {"id", "embedding"}
assert self.encoding_format in allowed_formats, f"mode must be one of {allowed_formats}, got '{self.encoding_format}'"
if self.encoding_format == "id":
assert self.num_spk is not None
if self.encoding_format == "embedding":
assert self.spk_embed_dim is not None
class FastSpeech2PhonemeEncoder(FastSpeech2EncoderBase):
def __init__(
self,
phone_vocab_size,
d_model,
num_layers,
num_heads,
ffn_kernel_size,
d_out,
dropout=0.1,
rel_pos=False,
spk_config: SpkConfig | None = None,
padding_set_zero: bool = True
):
super().__init__(
d_model=d_model,
num_layers=num_layers,
num_heads=num_heads,
ffn_kernel_size=ffn_kernel_size,
d_out=d_out,
dropout=dropout,
rel_pos=rel_pos,
padding_set_zero=padding_set_zero
)
self.phone_embed = Embedding(phone_vocab_size, d_model)
self.spk_config = spk_config
if spk_config is not None:
if spk_config.encoding_format == "id":
self.spk_embed_proj = Embedding(
spk_config.num_spk + 1, d_model
)
elif spk_config.encoding_format == "embedding":
self.spk_embed_proj = Linear(spk_config.spk_embed_dim, d_model)
def forward(
self, phoneme: torch.Tensor, lengths: Sequence[int], spk: torch.Tensor
):
x = self.embed_scale * self.phone_embed(phoneme)
x = self.pos_encoding(x, lengths)
x = F.dropout(x, p=self.dropout, training=self.training)
padding_mask = ~create_mask_from_length(lengths).to(phoneme.device)
x = self.layers(x, padding_mask=padding_mask)
if self.spk_config is not None:
spk_embed = self.spk_embed_proj(spk).unsqueeze(1)
x = x + spk_embed
x = self.out_proj(x)
return {"output": x, "mask": ~padding_mask}
class FastSpeech2MIDIEncoder(FastSpeech2PhonemeEncoder):
def __init__(
self,
phone_vocab_size: int,
midi_vocab_size: int,
slur_vocab_size: int,
spk_config: SpkConfig | None,
d_model: int,
num_layers: int,
num_heads: int,
ffn_kernel_size: int,
d_out: int,
dropout: float = 0.1,
rel_pos: bool = True,
padding_set_zero: bool = True
):
super().__init__(
phone_vocab_size=phone_vocab_size,
d_model=d_model,
num_layers=num_layers,
num_heads=num_heads,
ffn_kernel_size=ffn_kernel_size,
d_out=d_out,
dropout=dropout,
rel_pos=rel_pos,
spk_config=spk_config,
padding_set_zero=padding_set_zero
)
self.midi_embed = Embedding(midi_vocab_size, d_model, padding_idx=0)
self.midi_dur_embed = Linear(1, d_model)
self.is_slur_embed = Embedding(slur_vocab_size, d_model)
def forward(
self,
phoneme: torch.Tensor,
midi: torch.Tensor,
midi_duration: torch.Tensor,
is_slur: torch.Tensor,
lengths: Sequence[int],
spk: torch.Tensor | None = None,
):
x = self.embed_scale * self.phone_embed(phoneme)
midi_embedding = self.midi_embed(midi)
midi_dur_embedding = self.midi_dur_embed(midi_duration[:, :, None])
slur_embedding = self.is_slur_embed(is_slur)
x = x + midi_embedding + midi_dur_embedding + slur_embedding
x = self.pos_encoding(x, lengths)
x = F.dropout(x, p=self.dropout, training=self.training)
padding_mask = ~create_mask_from_length(lengths).to(phoneme.device)
x = self.layers(x, padding_mask=padding_mask)
if self.spk_config is not None:
spk_embed = self.spk_embed_proj(spk).unsqueeze(1)
x = x + spk_embed
x = self.out_proj(x)
return {"output": x, "mask": ~padding_mask}
class FastSpeech2PitchEncoder(FastSpeech2EncoderBase):
def __init__(
self,
phone_vocab_size,
d_model,
num_layers,
num_heads,
ffn_kernel_size,
d_out,
dropout=0.1,
rel_pos=False,
padding_set_zero=True
):
super().__init__(
d_model=d_model,
num_layers=num_layers,
num_heads=num_heads,
ffn_kernel_size=ffn_kernel_size,
d_out=d_out,
dropout=dropout,
rel_pos=rel_pos,
padding_set_zero=padding_set_zero
)
self.phone_embed = Embedding(phone_vocab_size, d_model)
self.pitch_embed = Embedding(300, d_model)
def forward(self, phoneme: torch.Tensor, lengths: Sequence[int]):
x = self.embed_scale * self.phone_embed(phoneme)
x = self.pos_encoding(x, lengths)
x = F.dropout(x, p=self.dropout, training=self.training)
padding_mask = ~create_mask_from_length(lengths).to(phoneme.device)
x = self.layers(x, padding_mask=padding_mask)
x = self.out_proj(x)
return {"output": x, "mask": ~padding_mask}
def encode_pitch(self, f0, uv):
f0_denorm = denorm_f0(f0, uv)
pitch = f0_to_coarse(f0_denorm)
pitch_embed = self.pitch_embed(pitch)
return {"output": pitch_embed}