STAR / models /content_encoder /midi_encoder.py
Yixuan Li
first commit
4853fdc
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}