work on pip package
This commit is contained in:
@@ -3,16 +3,19 @@ import math
|
||||
import torch
|
||||
from torch import nn
|
||||
|
||||
|
||||
class ConvolutionModule(nn.Module):
|
||||
"""ConvolutionModule in Conformer model."""
|
||||
|
||||
def __init__(self,
|
||||
channels: int,
|
||||
kernel_size: int = 15,
|
||||
activation: nn.Module = nn.ReLU(),
|
||||
norm: str = "batch_norm",
|
||||
causal: bool = False,
|
||||
bias: bool = True):
|
||||
def __init__(
|
||||
self,
|
||||
channels: int,
|
||||
kernel_size: int = 15,
|
||||
activation: nn.Module = nn.ReLU(),
|
||||
norm: str = "batch_norm",
|
||||
causal: bool = False,
|
||||
bias: bool = True,
|
||||
):
|
||||
"""Construct an ConvolutionModule object.
|
||||
Args:
|
||||
channels (int): The number of channels of conv layers.
|
||||
@@ -51,7 +54,7 @@ class ConvolutionModule(nn.Module):
|
||||
bias=bias,
|
||||
)
|
||||
|
||||
assert norm in ['batch_norm', 'layer_norm']
|
||||
assert norm in ["batch_norm", "layer_norm"]
|
||||
if norm == "batch_norm":
|
||||
self.use_layer_norm = False
|
||||
self.norm = nn.BatchNorm1d(channels)
|
||||
@@ -95,13 +98,13 @@ class ConvolutionModule(nn.Module):
|
||||
|
||||
if self.lorder > 0:
|
||||
if cache.size(2) == 0: # cache_t == 0
|
||||
x = nn.functional.pad(x, (self.lorder, 0), 'constant', 0.0)
|
||||
x = nn.functional.pad(x, (self.lorder, 0), "constant", 0.0)
|
||||
else:
|
||||
assert cache.size(0) == x.size(0) # equal batch
|
||||
assert cache.size(1) == x.size(1) # equal channel
|
||||
x = torch.cat((cache, x), dim=2)
|
||||
assert (x.size(2) > self.lorder)
|
||||
new_cache = x[:, :, -self.lorder:]
|
||||
assert x.size(2) > self.lorder
|
||||
new_cache = x[:, :, -self.lorder :]
|
||||
else:
|
||||
# It's better we just return None if no cache is required,
|
||||
# However, for JIT export, here we just fake one tensor instead of
|
||||
@@ -126,6 +129,7 @@ class ConvolutionModule(nn.Module):
|
||||
|
||||
return x.transpose(1, 2), new_cache
|
||||
|
||||
|
||||
class PositionwiseFeedForward(torch.nn.Module):
|
||||
"""Positionwise feed forward layer.
|
||||
|
||||
@@ -140,11 +144,11 @@ class PositionwiseFeedForward(torch.nn.Module):
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
idim: int,
|
||||
hidden_units: int,
|
||||
dropout_rate: float,
|
||||
activation: torch.nn.Module = torch.nn.ReLU(),
|
||||
self,
|
||||
idim: int,
|
||||
hidden_units: int,
|
||||
dropout_rate: float,
|
||||
activation: torch.nn.Module = torch.nn.ReLU(),
|
||||
):
|
||||
"""Construct a PositionwiseFeedForward object."""
|
||||
super(PositionwiseFeedForward, self).__init__()
|
||||
@@ -163,6 +167,7 @@ class PositionwiseFeedForward(torch.nn.Module):
|
||||
"""
|
||||
return self.w_2(self.dropout(self.activation(self.w_1(xs))))
|
||||
|
||||
|
||||
class Swish(torch.nn.Module):
|
||||
"""Construct an Swish object."""
|
||||
|
||||
@@ -170,6 +175,7 @@ class Swish(torch.nn.Module):
|
||||
"""Return Swish activation function."""
|
||||
return x * torch.sigmoid(x)
|
||||
|
||||
|
||||
class MultiHeadedAttention(nn.Module):
|
||||
"""Multi-Head Attention layer.
|
||||
|
||||
@@ -180,11 +186,9 @@ class MultiHeadedAttention(nn.Module):
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
n_head: int,
|
||||
n_feat: int,
|
||||
dropout_rate: float,
|
||||
key_bias: bool = True):
|
||||
def __init__(
|
||||
self, n_head: int, n_feat: int, dropout_rate: float, key_bias: bool = True
|
||||
):
|
||||
"""Construct an MultiHeadedAttention object."""
|
||||
super().__init__()
|
||||
assert n_feat % n_head == 0
|
||||
@@ -229,7 +233,7 @@ class MultiHeadedAttention(nn.Module):
|
||||
self,
|
||||
value: torch.Tensor,
|
||||
scores: torch.Tensor,
|
||||
mask: torch.Tensor = torch.ones((0, 0, 0), dtype=torch.bool)
|
||||
mask: torch.Tensor = torch.ones((0, 0, 0), dtype=torch.bool),
|
||||
) -> torch.Tensor:
|
||||
"""Compute attention context vector.
|
||||
|
||||
@@ -247,23 +251,24 @@ class MultiHeadedAttention(nn.Module):
|
||||
|
||||
"""
|
||||
n_batch = value.size(0)
|
||||
|
||||
|
||||
if mask.size(2) > 0: # time2 > 0
|
||||
mask = mask.unsqueeze(1).eq(0) # (batch, 1, *, time2)
|
||||
# For last chunk, time2 might be larger than scores.size(-1)
|
||||
mask = mask[:, :, :, :scores.size(-1)] # (batch, 1, *, time2)
|
||||
scores = scores.masked_fill(mask, -float('inf'))
|
||||
mask = mask[:, :, :, : scores.size(-1)] # (batch, 1, *, time2)
|
||||
scores = scores.masked_fill(mask, -float("inf"))
|
||||
attn = torch.softmax(scores, dim=-1).masked_fill(
|
||||
mask, 0.0) # (batch, head, time1, time2)
|
||||
mask, 0.0
|
||||
) # (batch, head, time1, time2)
|
||||
|
||||
else:
|
||||
attn = torch.softmax(scores, dim=-1) # (batch, head, time1, time2)
|
||||
|
||||
p_attn = self.dropout(attn)
|
||||
x = torch.matmul(p_attn, value) # (batch, head, time1, d_k)
|
||||
x = (x.transpose(1, 2).contiguous().view(n_batch, -1,
|
||||
self.h * self.d_k)
|
||||
) # (batch, time1, d_model)
|
||||
x = (
|
||||
x.transpose(1, 2).contiguous().view(n_batch, -1, self.h * self.d_k)
|
||||
) # (batch, time1, d_model)
|
||||
|
||||
return self.linear_out(x) # (batch, time1, d_model)
|
||||
|
||||
@@ -274,7 +279,7 @@ class MultiHeadedAttention(nn.Module):
|
||||
value: torch.Tensor,
|
||||
mask: torch.Tensor = torch.ones((0, 0, 0), dtype=torch.bool),
|
||||
pos_emb: torch.Tensor = torch.empty(0),
|
||||
cache: torch.Tensor = torch.zeros((0, 0, 0, 0))
|
||||
cache: torch.Tensor = torch.zeros((0, 0, 0, 0)),
|
||||
) -> Tuple[torch.Tensor, torch.Tensor]:
|
||||
"""Compute scaled dot product attention.
|
||||
|
||||
@@ -308,9 +313,7 @@ class MultiHeadedAttention(nn.Module):
|
||||
"""
|
||||
q, k, v = self.forward_qkv(query, key, value)
|
||||
if cache.size(0) > 0:
|
||||
key_cache, value_cache = torch.split(cache,
|
||||
cache.size(-1) // 2,
|
||||
dim=-1)
|
||||
key_cache, value_cache = torch.split(cache, cache.size(-1) // 2, dim=-1)
|
||||
k = torch.cat([key_cache, k], dim=2)
|
||||
v = torch.cat([value_cache, v], dim=2)
|
||||
new_cache = torch.cat((k, v), dim=-1)
|
||||
@@ -328,11 +331,9 @@ class RelPositionMultiHeadedAttention(MultiHeadedAttention):
|
||||
dropout_rate (float): Dropout rate.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
n_head: int,
|
||||
n_feat: int,
|
||||
dropout_rate: float,
|
||||
key_bias: bool = True):
|
||||
def __init__(
|
||||
self, n_head: int, n_feat: int, dropout_rate: float, key_bias: bool = True
|
||||
):
|
||||
"""Construct an RelPositionMultiHeadedAttention object."""
|
||||
super().__init__(n_head, n_feat, dropout_rate, key_bias)
|
||||
# linear transformation for positional encoding
|
||||
@@ -355,14 +356,12 @@ class RelPositionMultiHeadedAttention(MultiHeadedAttention):
|
||||
torch.Tensor: Output tensor.
|
||||
|
||||
"""
|
||||
zero_pad = torch.zeros((x.size()[0], x.size()[1], x.size()[2], 1),
|
||||
device=x.device,
|
||||
dtype=x.dtype)
|
||||
zero_pad = torch.zeros(
|
||||
(x.size()[0], x.size()[1], x.size()[2], 1), device=x.device, dtype=x.dtype
|
||||
)
|
||||
x_padded = torch.cat([zero_pad, x], dim=-1)
|
||||
|
||||
x_padded = x_padded.view(x.size()[0],
|
||||
x.size()[1],
|
||||
x.size(3) + 1, x.size(2))
|
||||
x_padded = x_padded.view(x.size()[0], x.size()[1], x.size(3) + 1, x.size(2))
|
||||
x = x_padded[:, :, 1:].view_as(x)[
|
||||
:, :, :, : x.size(-1) // 2 + 1
|
||||
] # only keep the positions from 0 to time2
|
||||
@@ -375,7 +374,7 @@ class RelPositionMultiHeadedAttention(MultiHeadedAttention):
|
||||
value: torch.Tensor,
|
||||
mask: torch.Tensor = torch.ones((0, 0, 0), dtype=torch.bool),
|
||||
pos_emb: torch.Tensor = torch.empty(0),
|
||||
cache: torch.Tensor = torch.zeros((0, 0, 0, 0))
|
||||
cache: torch.Tensor = torch.zeros((0, 0, 0, 0)),
|
||||
) -> Tuple[torch.Tensor, torch.Tensor]:
|
||||
"""Compute 'Scaled Dot Product Attention' with rel. positional encoding.
|
||||
Args:
|
||||
@@ -399,9 +398,7 @@ class RelPositionMultiHeadedAttention(MultiHeadedAttention):
|
||||
q = q.transpose(1, 2) # (batch, time1, head, d_k)
|
||||
|
||||
if cache.size(0) > 0:
|
||||
key_cache, value_cache = torch.split(cache,
|
||||
cache.size(-1) // 2,
|
||||
dim=-1)
|
||||
key_cache, value_cache = torch.split(cache, cache.size(-1) // 2, dim=-1)
|
||||
k = torch.cat([key_cache, k], dim=2)
|
||||
v = torch.cat([value_cache, v], dim=2)
|
||||
# NOTE(xcsong): We do cache slicing in encoder.forward_chunk, since it's
|
||||
@@ -431,15 +428,15 @@ class RelPositionMultiHeadedAttention(MultiHeadedAttention):
|
||||
matrix_bd = self.rel_shift(matrix_bd)
|
||||
|
||||
scores = (matrix_ac + matrix_bd) / math.sqrt(
|
||||
self.d_k) # (batch, head, time1, time2)
|
||||
self.d_k
|
||||
) # (batch, head, time1, time2)
|
||||
|
||||
return self.forward_attention(v, scores, mask), new_cache
|
||||
|
||||
|
||||
|
||||
def subsequent_mask(
|
||||
size: int,
|
||||
device: torch.device = torch.device("cpu"),
|
||||
size: int,
|
||||
device: torch.device = torch.device("cpu"),
|
||||
) -> torch.Tensor:
|
||||
"""Create mask for subsequent steps (size, size).
|
||||
|
||||
@@ -474,11 +471,11 @@ def subsequent_mask(
|
||||
|
||||
|
||||
def subsequent_chunk_mask(
|
||||
size: int,
|
||||
chunk_size: int,
|
||||
num_left_chunks: int = -1,
|
||||
device: torch.device = torch.device("cpu"),
|
||||
) -> torch.Tensor:
|
||||
size: int,
|
||||
chunk_size: int,
|
||||
num_left_chunks: int = -1,
|
||||
device: torch.device = torch.device("cpu"),
|
||||
) -> torch.Tensor:
|
||||
"""Create mask for subsequent steps (size, size) with chunk size,
|
||||
this is for streaming encoder
|
||||
|
||||
@@ -510,15 +507,18 @@ def subsequent_chunk_mask(
|
||||
ret[i, start:ending] = True
|
||||
return ret
|
||||
|
||||
def add_optional_chunk_mask(xs: torch.Tensor,
|
||||
masks: torch.Tensor,
|
||||
use_dynamic_chunk: bool,
|
||||
use_dynamic_left_chunk: bool,
|
||||
decoding_chunk_size: int,
|
||||
static_chunk_size: int,
|
||||
num_decoding_left_chunks: int,
|
||||
enable_full_context: bool = True):
|
||||
""" Apply optional mask for encoder.
|
||||
|
||||
def add_optional_chunk_mask(
|
||||
xs: torch.Tensor,
|
||||
masks: torch.Tensor,
|
||||
use_dynamic_chunk: bool,
|
||||
use_dynamic_left_chunk: bool,
|
||||
decoding_chunk_size: int,
|
||||
static_chunk_size: int,
|
||||
num_decoding_left_chunks: int,
|
||||
enable_full_context: bool = True,
|
||||
):
|
||||
"""Apply optional mask for encoder.
|
||||
|
||||
Args:
|
||||
xs (torch.Tensor): padded input, (B, L, D), L for max length
|
||||
@@ -557,7 +557,7 @@ def add_optional_chunk_mask(xs: torch.Tensor,
|
||||
# chunk size is either [1, 25] or full context(max_len).
|
||||
# Since we use 4 times subsampling and allow up to 1s(100 frames)
|
||||
# delay, the maximum frame is 100 / 4 = 25.
|
||||
chunk_size = torch.randint(1, max_len, (1, )).item()
|
||||
chunk_size = torch.randint(1, max_len, (1,)).item()
|
||||
num_left_chunks = -1
|
||||
if chunk_size > max_len // 2 and enable_full_context:
|
||||
chunk_size = max_len
|
||||
@@ -565,18 +565,17 @@ def add_optional_chunk_mask(xs: torch.Tensor,
|
||||
chunk_size = chunk_size % 25 + 1
|
||||
if use_dynamic_left_chunk:
|
||||
max_left_chunks = (max_len - 1) // chunk_size
|
||||
num_left_chunks = torch.randint(0, max_left_chunks,
|
||||
(1, )).item()
|
||||
chunk_masks = subsequent_chunk_mask(xs.size(1), chunk_size,
|
||||
num_left_chunks,
|
||||
xs.device) # (L, L)
|
||||
num_left_chunks = torch.randint(0, max_left_chunks, (1,)).item()
|
||||
chunk_masks = subsequent_chunk_mask(
|
||||
xs.size(1), chunk_size, num_left_chunks, xs.device
|
||||
) # (L, L)
|
||||
chunk_masks = chunk_masks.unsqueeze(0) # (1, L, L)
|
||||
chunk_masks = masks & chunk_masks # (B, L, L)
|
||||
elif static_chunk_size > 0:
|
||||
num_left_chunks = num_decoding_left_chunks
|
||||
chunk_masks = subsequent_chunk_mask(xs.size(1), static_chunk_size,
|
||||
num_left_chunks,
|
||||
xs.device) # (L, L)
|
||||
chunk_masks = subsequent_chunk_mask(
|
||||
xs.size(1), static_chunk_size, num_left_chunks, xs.device
|
||||
) # (L, L)
|
||||
chunk_masks = chunk_masks.unsqueeze(0) # (1, L, L)
|
||||
chunk_masks = masks & chunk_masks # (B, L, L)
|
||||
else:
|
||||
@@ -630,7 +629,8 @@ class ConformerEncoderLayer(nn.Module):
|
||||
if self.conv_module is not None:
|
||||
self.norm_conv = nn.LayerNorm(size, eps=1e-5) # for the CNN module
|
||||
self.norm_final = nn.LayerNorm(
|
||||
size, eps=1e-5) # for the final output of the block
|
||||
size, eps=1e-5
|
||||
) # for the final output of the block
|
||||
self.dropout = nn.Dropout(dropout_rate)
|
||||
self.size = size
|
||||
self.normalize_before = normalize_before
|
||||
@@ -671,8 +671,7 @@ class ConformerEncoderLayer(nn.Module):
|
||||
residual = x
|
||||
if self.normalize_before:
|
||||
x = self.norm_ff_macaron(x)
|
||||
x = residual + self.ff_scale * self.dropout(
|
||||
self.feed_forward_macaron(x))
|
||||
x = residual + self.ff_scale * self.dropout(self.feed_forward_macaron(x))
|
||||
if not self.normalize_before:
|
||||
x = self.norm_ff_macaron(x)
|
||||
|
||||
@@ -680,8 +679,7 @@ class ConformerEncoderLayer(nn.Module):
|
||||
residual = x
|
||||
if self.normalize_before:
|
||||
x = self.norm_mha(x)
|
||||
x_att, new_att_cache = self.self_attn(x, x, x, mask, pos_emb,
|
||||
att_cache)
|
||||
x_att, new_att_cache = self.self_attn(x, x, x, mask, pos_emb, att_cache)
|
||||
x = residual + self.dropout(x_att)
|
||||
if not self.normalize_before:
|
||||
x = self.norm_mha(x)
|
||||
@@ -712,7 +710,6 @@ class ConformerEncoderLayer(nn.Module):
|
||||
x = self.norm_final(x)
|
||||
|
||||
return x, mask, new_att_cache, new_cnn_cache
|
||||
|
||||
|
||||
|
||||
class EspnetRelPositionalEncoding(torch.nn.Module):
|
||||
@@ -770,8 +767,9 @@ class EspnetRelPositionalEncoding(torch.nn.Module):
|
||||
pe = torch.cat([pe_positive, pe_negative], dim=1)
|
||||
self.pe = pe.to(device=x.device, dtype=x.dtype)
|
||||
|
||||
def forward(self, x: torch.Tensor, offset: Union[int, torch.Tensor] = 0) \
|
||||
-> Tuple[torch.Tensor, torch.Tensor]:
|
||||
def forward(
|
||||
self, x: torch.Tensor, offset: Union[int, torch.Tensor] = 0
|
||||
) -> Tuple[torch.Tensor, torch.Tensor]:
|
||||
"""Add positional encoding.
|
||||
|
||||
Args:
|
||||
@@ -785,11 +783,11 @@ class EspnetRelPositionalEncoding(torch.nn.Module):
|
||||
x = x * self.xscale
|
||||
pos_emb = self.position_encoding(size=x.size(1), offset=offset)
|
||||
return self.dropout(x), self.dropout(pos_emb)
|
||||
|
||||
def position_encoding(self,
|
||||
offset: Union[int, torch.Tensor],
|
||||
size: int) -> torch.Tensor:
|
||||
""" For getting encoding in a streaming fashion
|
||||
|
||||
def position_encoding(
|
||||
self, offset: Union[int, torch.Tensor], size: int
|
||||
) -> torch.Tensor:
|
||||
"""For getting encoding in a streaming fashion
|
||||
|
||||
Attention!!!!!
|
||||
we apply dropout only once at the whole utterance level in a none
|
||||
@@ -806,12 +804,11 @@ class EspnetRelPositionalEncoding(torch.nn.Module):
|
||||
"""
|
||||
pos_emb = self.pe[
|
||||
:,
|
||||
self.pe.size(1) // 2 - size + 1: self.pe.size(1) // 2 + size,
|
||||
self.pe.size(1) // 2 - size + 1 : self.pe.size(1) // 2 + size,
|
||||
]
|
||||
return pos_emb
|
||||
|
||||
|
||||
|
||||
class LinearEmbed(torch.nn.Module):
|
||||
"""Linear transform the input without subsampling
|
||||
|
||||
@@ -822,8 +819,9 @@ class LinearEmbed(torch.nn.Module):
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, idim: int, odim: int, dropout_rate: float,
|
||||
pos_enc_class: torch.nn.Module):
|
||||
def __init__(
|
||||
self, idim: int, odim: int, dropout_rate: float, pos_enc_class: torch.nn.Module
|
||||
):
|
||||
"""Construct an linear object."""
|
||||
super().__init__()
|
||||
self.out = torch.nn.Sequential(
|
||||
@@ -831,16 +829,15 @@ class LinearEmbed(torch.nn.Module):
|
||||
torch.nn.LayerNorm(odim, eps=1e-5),
|
||||
torch.nn.Dropout(dropout_rate),
|
||||
)
|
||||
self.pos_enc = pos_enc_class #rel_pos_espnet
|
||||
|
||||
def position_encoding(self, offset: Union[int, torch.Tensor],
|
||||
size: int) -> torch.Tensor:
|
||||
self.pos_enc = pos_enc_class # rel_pos_espnet
|
||||
|
||||
def position_encoding(
|
||||
self, offset: Union[int, torch.Tensor], size: int
|
||||
) -> torch.Tensor:
|
||||
return self.pos_enc.position_encoding(offset, size)
|
||||
|
||||
def forward(
|
||||
self,
|
||||
x: torch.Tensor,
|
||||
offset: Union[int, torch.Tensor] = 0
|
||||
self, x: torch.Tensor, offset: Union[int, torch.Tensor] = 0
|
||||
) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
|
||||
"""Input x.
|
||||
|
||||
@@ -894,16 +891,14 @@ def make_pad_mask(lengths: torch.Tensor, max_len: int = 0) -> torch.Tensor:
|
||||
"""
|
||||
batch_size = lengths.size(0)
|
||||
max_len = max_len if max_len > 0 else lengths.max().item()
|
||||
seq_range = torch.arange(0,
|
||||
max_len,
|
||||
dtype=torch.int64,
|
||||
device=lengths.device)
|
||||
seq_range = torch.arange(0, max_len, dtype=torch.int64, device=lengths.device)
|
||||
seq_range_expand = seq_range.unsqueeze(0).expand(batch_size, max_len)
|
||||
seq_length_expand = lengths.unsqueeze(-1)
|
||||
mask = seq_range_expand >= seq_length_expand
|
||||
return mask
|
||||
|
||||
#https://github.com/FunAudioLLM/CosyVoice/blob/main/examples/magicdata-read/cosyvoice/conf/cosyvoice.yaml
|
||||
|
||||
# https://github.com/FunAudioLLM/CosyVoice/blob/main/examples/magicdata-read/cosyvoice/conf/cosyvoice.yaml
|
||||
class ConformerEncoder(torch.nn.Module):
|
||||
"""Conformer encoder module."""
|
||||
|
||||
@@ -917,14 +912,14 @@ class ConformerEncoder(torch.nn.Module):
|
||||
dropout_rate: float = 0.1,
|
||||
positional_dropout_rate: float = 0.1,
|
||||
attention_dropout_rate: float = 0.0,
|
||||
input_layer: str = 'linear',
|
||||
pos_enc_layer_type: str = 'rel_pos_espnet',
|
||||
input_layer: str = "linear",
|
||||
pos_enc_layer_type: str = "rel_pos_espnet",
|
||||
normalize_before: bool = True,
|
||||
static_chunk_size: int = 1, # 1: causal_mask; 0: full_mask
|
||||
static_chunk_size: int = 1, # 1: causal_mask; 0: full_mask
|
||||
use_dynamic_chunk: bool = False,
|
||||
use_dynamic_left_chunk: bool = False,
|
||||
positionwise_conv_kernel_size: int = 1,
|
||||
macaron_style: bool =False,
|
||||
macaron_style: bool = False,
|
||||
selfattention_layer_type: str = "rel_selfattn",
|
||||
activation_type: str = "swish",
|
||||
use_cnn_module: bool = False,
|
||||
@@ -953,13 +948,17 @@ class ConformerEncoder(torch.nn.Module):
|
||||
"""
|
||||
super().__init__()
|
||||
self.output_size = output_size
|
||||
self.embed = LinearEmbed(input_size, output_size, dropout_rate,
|
||||
EspnetRelPositionalEncoding(output_size, positional_dropout_rate))
|
||||
self.embed = LinearEmbed(
|
||||
input_size,
|
||||
output_size,
|
||||
dropout_rate,
|
||||
EspnetRelPositionalEncoding(output_size, positional_dropout_rate),
|
||||
)
|
||||
self.normalize_before = normalize_before
|
||||
self.after_norm = torch.nn.LayerNorm(output_size, eps=1e-5)
|
||||
self.gradient_checkpointing = gradient_checkpointing
|
||||
self.use_dynamic_chunk = use_dynamic_chunk
|
||||
|
||||
|
||||
self.static_chunk_size = static_chunk_size
|
||||
self.use_dynamic_chunk = use_dynamic_chunk
|
||||
self.use_dynamic_left_chunk = use_dynamic_left_chunk
|
||||
@@ -980,40 +979,60 @@ class ConformerEncoder(torch.nn.Module):
|
||||
activation,
|
||||
)
|
||||
# convolution module definition
|
||||
convolution_layer_args = (output_size, cnn_module_kernel, activation,
|
||||
cnn_module_norm, causal)
|
||||
convolution_layer_args = (
|
||||
output_size,
|
||||
cnn_module_kernel,
|
||||
activation,
|
||||
cnn_module_norm,
|
||||
causal,
|
||||
)
|
||||
|
||||
self.encoders = torch.nn.ModuleList([
|
||||
ConformerEncoderLayer(
|
||||
output_size,
|
||||
RelPositionMultiHeadedAttention(
|
||||
*encoder_selfattn_layer_args),
|
||||
PositionwiseFeedForward(*positionwise_layer_args),
|
||||
PositionwiseFeedForward(
|
||||
*positionwise_layer_args) if macaron_style else None,
|
||||
ConvolutionModule(
|
||||
*convolution_layer_args) if use_cnn_module else None,
|
||||
dropout_rate,
|
||||
normalize_before,
|
||||
) for _ in range(num_blocks)
|
||||
])
|
||||
|
||||
def forward_layers(self, xs: torch.Tensor, chunk_masks: torch.Tensor,
|
||||
self.encoders = torch.nn.ModuleList(
|
||||
[
|
||||
ConformerEncoderLayer(
|
||||
output_size,
|
||||
RelPositionMultiHeadedAttention(*encoder_selfattn_layer_args),
|
||||
PositionwiseFeedForward(*positionwise_layer_args),
|
||||
(
|
||||
PositionwiseFeedForward(*positionwise_layer_args)
|
||||
if macaron_style
|
||||
else None
|
||||
),
|
||||
(
|
||||
ConvolutionModule(*convolution_layer_args)
|
||||
if use_cnn_module
|
||||
else None
|
||||
),
|
||||
dropout_rate,
|
||||
normalize_before,
|
||||
)
|
||||
for _ in range(num_blocks)
|
||||
]
|
||||
)
|
||||
|
||||
def forward_layers(
|
||||
self,
|
||||
xs: torch.Tensor,
|
||||
chunk_masks: torch.Tensor,
|
||||
pos_emb: torch.Tensor,
|
||||
mask_pad: torch.Tensor) -> torch.Tensor:
|
||||
mask_pad: torch.Tensor,
|
||||
) -> torch.Tensor:
|
||||
for layer in self.encoders:
|
||||
xs, chunk_masks, _, _ = layer(xs, chunk_masks, pos_emb, mask_pad)
|
||||
return xs
|
||||
|
||||
@torch.jit.unused
|
||||
def forward_layers_checkpointed(self, xs: torch.Tensor,
|
||||
chunk_masks: torch.Tensor,
|
||||
pos_emb: torch.Tensor,
|
||||
mask_pad: torch.Tensor) -> torch.Tensor:
|
||||
def forward_layers_checkpointed(
|
||||
self,
|
||||
xs: torch.Tensor,
|
||||
chunk_masks: torch.Tensor,
|
||||
pos_emb: torch.Tensor,
|
||||
mask_pad: torch.Tensor,
|
||||
) -> torch.Tensor:
|
||||
for layer in self.encoders:
|
||||
xs, chunk_masks, _, _ = ckpt.checkpoint(layer.__call__, xs,
|
||||
chunk_masks, pos_emb,
|
||||
mask_pad)
|
||||
xs, chunk_masks, _, _ = ckpt.checkpoint(
|
||||
layer.__call__, xs, chunk_masks, pos_emb, mask_pad
|
||||
)
|
||||
return xs
|
||||
|
||||
def forward(
|
||||
@@ -1047,18 +1066,20 @@ class ConformerEncoder(torch.nn.Module):
|
||||
https://discuss.pytorch.org/t/any-different-between-model-input-and-model-forward-input/3690/2
|
||||
"""
|
||||
T = xs.size(1)
|
||||
masks = pad_mask.to(torch.bool).unsqueeze(1) # (B, 1, T)
|
||||
masks = pad_mask.to(torch.bool).unsqueeze(1) # (B, 1, T)
|
||||
xs, pos_emb = self.embed(xs)
|
||||
mask_pad = masks # (B, 1, T/subsample_rate)
|
||||
chunk_masks = add_optional_chunk_mask(xs, masks,
|
||||
self.use_dynamic_chunk,
|
||||
self.use_dynamic_left_chunk,
|
||||
decoding_chunk_size,
|
||||
self.static_chunk_size,
|
||||
num_decoding_left_chunks)
|
||||
chunk_masks = add_optional_chunk_mask(
|
||||
xs,
|
||||
masks,
|
||||
self.use_dynamic_chunk,
|
||||
self.use_dynamic_left_chunk,
|
||||
decoding_chunk_size,
|
||||
self.static_chunk_size,
|
||||
num_decoding_left_chunks,
|
||||
)
|
||||
if self.gradient_checkpointing and self.training:
|
||||
xs = self.forward_layers_checkpointed(xs, chunk_masks, pos_emb,
|
||||
mask_pad)
|
||||
xs = self.forward_layers_checkpointed(xs, chunk_masks, pos_emb, mask_pad)
|
||||
else:
|
||||
xs = self.forward_layers(xs, chunk_masks, pos_emb, mask_pad)
|
||||
if self.normalize_before:
|
||||
@@ -1067,4 +1088,3 @@ class ConformerEncoder(torch.nn.Module):
|
||||
# return the masks before encoder layers, and the masks will be used
|
||||
# for cross attention with decoder later
|
||||
return xs, masks
|
||||
|
||||
|
||||
@@ -2,39 +2,42 @@ import re
|
||||
from opencc import OpenCC
|
||||
|
||||
|
||||
t2s_converter = OpenCC('t2s')
|
||||
s2t_converter = OpenCC('s2t')
|
||||
t2s_converter = OpenCC("t2s")
|
||||
s2t_converter = OpenCC("s2t")
|
||||
|
||||
|
||||
EMOJI_PATTERN = re.compile(
|
||||
"["
|
||||
"\U0001F600-\U0001F64F" # Emoticons
|
||||
"]+", flags=re.UNICODE
|
||||
"\U0001f600-\U0001f64f" # Emoticons
|
||||
"]+",
|
||||
flags=re.UNICODE,
|
||||
)
|
||||
|
||||
# 创建一个翻译表,用于替换和移除字符
|
||||
TRANSLATION_TABLE = str.maketrans({
|
||||
'-': ' ', # 将 '-' 替换为空格
|
||||
',': None,
|
||||
'.': None,
|
||||
',': None,
|
||||
'。': None,
|
||||
'!': None,
|
||||
'!': None,
|
||||
'?': None,
|
||||
'?': None,
|
||||
'…': None,
|
||||
';': None,
|
||||
';': None,
|
||||
':': None,
|
||||
':': None,
|
||||
'\u3000': ' ', # 将全角空格替换为空格
|
||||
})
|
||||
TRANSLATION_TABLE = str.maketrans(
|
||||
{
|
||||
"-": " ", # 将 '-' 替换为空格
|
||||
",": None,
|
||||
".": None,
|
||||
",": None,
|
||||
"。": None,
|
||||
"!": None,
|
||||
"!": None,
|
||||
"?": None,
|
||||
"?": None,
|
||||
"…": None,
|
||||
";": None,
|
||||
";": None,
|
||||
":": None,
|
||||
":": None,
|
||||
"\u3000": " ", # 将全角空格替换为空格
|
||||
}
|
||||
)
|
||||
|
||||
# 替换括号中的内容,包括中括号和小括号
|
||||
BACKSLASH_PATTERN = re.compile(r'\(.*?\)|\[.*?\]')
|
||||
BACKSLASH_PATTERN = re.compile(r"\(.*?\)|\[.*?\]")
|
||||
|
||||
SPACE_PATTERN = re.compile('(?<!^)\s+(?!$)')
|
||||
SPACE_PATTERN = re.compile("(?<!^)\s+(?!$)")
|
||||
|
||||
|
||||
def normalize_text(text, language, strip=True):
|
||||
@@ -45,10 +48,10 @@ def normalize_text(text, language, strip=True):
|
||||
text = text.translate(TRANSLATION_TABLE)
|
||||
|
||||
# Step 2: 移除表情符号
|
||||
text = EMOJI_PATTERN.sub('', text)
|
||||
text = EMOJI_PATTERN.sub("", text)
|
||||
|
||||
# Step 3: 连续空白字符替换为单个空格,首位除外
|
||||
text = SPACE_PATTERN.sub(' ', text)
|
||||
text = SPACE_PATTERN.sub(" ", text)
|
||||
|
||||
# Step 4: 去除首尾空白字符(如果需要)
|
||||
if strip:
|
||||
|
||||
@@ -19,7 +19,7 @@ from .zh_num2words import TextNorm as zh_num2words
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
|
||||
|
||||
#copy from https://github.com/coqui-ai/TTS/blob/dbf1a08a0d4e47fdad6172e433eeb34bc6b13b4e/TTS/tts/layers/xtts/tokenizer.py
|
||||
# copy from https://github.com/coqui-ai/TTS/blob/dbf1a08a0d4e47fdad6172e433eeb34bc6b13b4e/TTS/tts/layers/xtts/tokenizer.py
|
||||
def get_spacy_lang(lang):
|
||||
if lang == "zh":
|
||||
return Chinese()
|
||||
@@ -446,7 +446,9 @@ _ordinal_re = {
|
||||
"it": re.compile(r"([0-9]+)(º|°|ª|o|a|i|e)"),
|
||||
"pl": re.compile(r"([0-9]+)(º|ª|st|nd|rd|th)"),
|
||||
"ar": re.compile(r"([0-9]+)(ون|ين|ث|ر|ى)"),
|
||||
"cs": re.compile(r"([0-9]+)\.(?=\s|$)"), # In Czech, a dot is often used after the number to indicate ordinals.
|
||||
"cs": re.compile(
|
||||
r"([0-9]+)\.(?=\s|$)"
|
||||
), # In Czech, a dot is often used after the number to indicate ordinals.
|
||||
"ru": re.compile(r"([0-9]+)(-й|-я|-е|-ое|-ье|-го)"),
|
||||
"nl": re.compile(r"([0-9]+)(de|ste|e)"),
|
||||
"tr": re.compile(r"([0-9]+)(\.|inci|nci|uncu|üncü|\.)"),
|
||||
@@ -486,7 +488,9 @@ def _expand_decimal_point(m, lang="en"):
|
||||
|
||||
def _expand_currency(m, lang="en", currency="USD"):
|
||||
amount = float((re.sub(r"[^\d.]", "", m.group(0).replace(",", "."))))
|
||||
full_amount = num2words(amount, to="currency", currency=currency, lang=lang if lang != "cs" else "cz")
|
||||
full_amount = num2words(
|
||||
amount, to="currency", currency=currency, lang=lang if lang != "cs" else "cz"
|
||||
)
|
||||
|
||||
and_equivalents = {
|
||||
"en": ", ",
|
||||
@@ -530,13 +534,21 @@ def expand_numbers_multilingual(text, lang="en"):
|
||||
else:
|
||||
text = re.sub(_dot_number_re, _remove_dots, text)
|
||||
try:
|
||||
text = re.sub(_currency_re["GBP"], lambda m: _expand_currency(m, lang, "GBP"), text)
|
||||
text = re.sub(_currency_re["USD"], lambda m: _expand_currency(m, lang, "USD"), text)
|
||||
text = re.sub(_currency_re["EUR"], lambda m: _expand_currency(m, lang, "EUR"), text)
|
||||
text = re.sub(
|
||||
_currency_re["GBP"], lambda m: _expand_currency(m, lang, "GBP"), text
|
||||
)
|
||||
text = re.sub(
|
||||
_currency_re["USD"], lambda m: _expand_currency(m, lang, "USD"), text
|
||||
)
|
||||
text = re.sub(
|
||||
_currency_re["EUR"], lambda m: _expand_currency(m, lang, "EUR"), text
|
||||
)
|
||||
except:
|
||||
pass
|
||||
if lang != "tr":
|
||||
text = re.sub(_decimal_number_re, lambda m: _expand_decimal_point(m, lang), text)
|
||||
text = re.sub(
|
||||
_decimal_number_re, lambda m: _expand_decimal_point(m, lang), text
|
||||
)
|
||||
text = re.sub(_ordinal_re[lang], lambda m: _expand_ordinal(m, lang), text)
|
||||
text = re.sub(_number_re, lambda m: _expand_number(m, lang), text)
|
||||
return text
|
||||
@@ -582,7 +594,15 @@ def basic_cleaners(text):
|
||||
|
||||
def chinese_transliterate(text):
|
||||
return "".join(
|
||||
[p[0] for p in pypinyin.pinyin(text, style=pypinyin.Style.TONE3, heteronym=False, neutral_tone_with_five=True)]
|
||||
[
|
||||
p[0]
|
||||
for p in pypinyin.pinyin(
|
||||
text,
|
||||
style=pypinyin.Style.TONE3,
|
||||
heteronym=False,
|
||||
neutral_tone_with_five=True,
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@@ -597,7 +617,9 @@ def korean_transliterate(text):
|
||||
return r.translit(text)
|
||||
|
||||
|
||||
DEFAULT_VOCAB_FILE = os.path.join(os.path.dirname(os.path.realpath(__file__)), "vocab.json")
|
||||
DEFAULT_VOCAB_FILE = os.path.join(
|
||||
os.path.dirname(os.path.realpath(__file__)), "vocab.json"
|
||||
)
|
||||
|
||||
|
||||
class VoiceBpeTokenizer:
|
||||
@@ -639,7 +661,23 @@ class VoiceBpeTokenizer:
|
||||
# )
|
||||
|
||||
def preprocess_text(self, txt, lang):
|
||||
if lang in {"ar", "cs", "de", "en", "es", "fr", "hu", "it", "nl", "pl", "pt", "ru", "tr", "zh", "ko"}:
|
||||
if lang in {
|
||||
"ar",
|
||||
"cs",
|
||||
"de",
|
||||
"en",
|
||||
"es",
|
||||
"fr",
|
||||
"hu",
|
||||
"it",
|
||||
"nl",
|
||||
"pl",
|
||||
"pt",
|
||||
"ru",
|
||||
"tr",
|
||||
"zh",
|
||||
"ko",
|
||||
}:
|
||||
txt = multilingual_cleaners(txt, lang)
|
||||
if lang == "zh":
|
||||
txt = chinese_transliterate(txt)
|
||||
@@ -653,7 +691,7 @@ class VoiceBpeTokenizer:
|
||||
else:
|
||||
raise NotImplementedError(f"Language '{lang}' is not supported.")
|
||||
return txt
|
||||
|
||||
|
||||
def encode(self, txt, lang):
|
||||
lang = lang.split("-")[0] # remove the region
|
||||
self.check_input_length(txt, lang)
|
||||
@@ -671,12 +709,13 @@ class VoiceBpeTokenizer:
|
||||
txt = txt.replace("[STOP]", "")
|
||||
# txt = txt.replace("[UNK]", "")
|
||||
return txt
|
||||
|
||||
|
||||
#copy from https://github.com/huggingface/transformers/blob/main/src/transformers/tokenization_utils_base.py#L3936
|
||||
# copy from https://github.com/huggingface/transformers/blob/main/src/transformers/tokenization_utils_base.py#L3936
|
||||
def batch_decode(
|
||||
self,
|
||||
sequences: Union[List[int], List[List[int]], "np.ndarray", "torch.Tensor", "tf.Tensor"],
|
||||
sequences: Union[
|
||||
List[int], List[List[int]], "np.ndarray", "torch.Tensor", "tf.Tensor"
|
||||
],
|
||||
skip_special_tokens: bool = False,
|
||||
) -> List[str]:
|
||||
"""
|
||||
@@ -693,13 +732,10 @@ class VoiceBpeTokenizer:
|
||||
Returns:
|
||||
`List[str]`: The list of decoded sentences.
|
||||
"""
|
||||
return [
|
||||
self.decode(seq)
|
||||
for seq in sequences
|
||||
]
|
||||
|
||||
#https://github.com/coqui-ai/TTS/blob/dev/TTS/tts/layers/xtts/trainer/dataset.py#L202
|
||||
# def pad(self):
|
||||
return [self.decode(seq) for seq in sequences]
|
||||
|
||||
# https://github.com/coqui-ai/TTS/blob/dev/TTS/tts/layers/xtts/trainer/dataset.py#L202
|
||||
# def pad(self):
|
||||
|
||||
def __len__(self):
|
||||
return self.tokenizer.get_vocab_size()
|
||||
@@ -716,15 +752,27 @@ def test_expand_numbers_multilingual():
|
||||
("This is a 1st test", "This is a first test", "en"),
|
||||
("That will be $20 sir.", "That will be twenty dollars sir.", "en"),
|
||||
("That will be 20€ sir.", "That will be twenty euro sir.", "en"),
|
||||
("That will be 20.15€ sir.", "That will be twenty euro, fifteen cents sir.", "en"),
|
||||
(
|
||||
"That will be 20.15€ sir.",
|
||||
"That will be twenty euro, fifteen cents sir.",
|
||||
"en",
|
||||
),
|
||||
("That's 100,000.5.", "That's one hundred thousand point five.", "en"),
|
||||
# French
|
||||
("En 12,5 secondes.", "En douze virgule cinq secondes.", "fr"),
|
||||
("Il y avait 50 soldats.", "Il y avait cinquante soldats.", "fr"),
|
||||
("Ceci est un 1er test", "Ceci est un premier test", "fr"),
|
||||
("Cela vous fera $20 monsieur.", "Cela vous fera vingt dollars monsieur.", "fr"),
|
||||
(
|
||||
"Cela vous fera $20 monsieur.",
|
||||
"Cela vous fera vingt dollars monsieur.",
|
||||
"fr",
|
||||
),
|
||||
("Cela vous fera 20€ monsieur.", "Cela vous fera vingt euros monsieur.", "fr"),
|
||||
("Cela vous fera 20,15€ monsieur.", "Cela vous fera vingt euros et quinze centimes monsieur.", "fr"),
|
||||
(
|
||||
"Cela vous fera 20,15€ monsieur.",
|
||||
"Cela vous fera vingt euros et quinze centimes monsieur.",
|
||||
"fr",
|
||||
),
|
||||
("Ce sera 100.000,5.", "Ce sera cent mille virgule cinq.", "fr"),
|
||||
# German
|
||||
("In 12,5 Sekunden.", "In zwölf Komma fünf Sekunden.", "de"),
|
||||
@@ -732,21 +780,33 @@ def test_expand_numbers_multilingual():
|
||||
("Dies ist ein 1. Test", "Dies ist ein erste Test", "de"), # Issue with gender
|
||||
("Das macht $20 Herr.", "Das macht zwanzig Dollar Herr.", "de"),
|
||||
("Das macht 20€ Herr.", "Das macht zwanzig Euro Herr.", "de"),
|
||||
("Das macht 20,15€ Herr.", "Das macht zwanzig Euro und fünfzehn Cent Herr.", "de"),
|
||||
(
|
||||
"Das macht 20,15€ Herr.",
|
||||
"Das macht zwanzig Euro und fünfzehn Cent Herr.",
|
||||
"de",
|
||||
),
|
||||
# Spanish
|
||||
("En 12,5 segundos.", "En doce punto cinco segundos.", "es"),
|
||||
("Había 50 soldados.", "Había cincuenta soldados.", "es"),
|
||||
("Este es un 1er test", "Este es un primero test", "es"),
|
||||
("Eso le costará $20 señor.", "Eso le costará veinte dólares señor.", "es"),
|
||||
("Eso le costará 20€ señor.", "Eso le costará veinte euros señor.", "es"),
|
||||
("Eso le costará 20,15€ señor.", "Eso le costará veinte euros con quince céntimos señor.", "es"),
|
||||
(
|
||||
"Eso le costará 20,15€ señor.",
|
||||
"Eso le costará veinte euros con quince céntimos señor.",
|
||||
"es",
|
||||
),
|
||||
# Italian
|
||||
("In 12,5 secondi.", "In dodici virgola cinque secondi.", "it"),
|
||||
("C'erano 50 soldati.", "C'erano cinquanta soldati.", "it"),
|
||||
("Questo è un 1° test", "Questo è un primo test", "it"),
|
||||
("Ti costerà $20 signore.", "Ti costerà venti dollari signore.", "it"),
|
||||
("Ti costerà 20€ signore.", "Ti costerà venti euro signore.", "it"),
|
||||
("Ti costerà 20,15€ signore.", "Ti costerà venti euro e quindici centesimi signore.", "it"),
|
||||
(
|
||||
"Ti costerà 20,15€ signore.",
|
||||
"Ti costerà venti euro e quindici centesimi signore.",
|
||||
"it",
|
||||
),
|
||||
# Portuguese
|
||||
("Em 12,5 segundos.", "Em doze vírgula cinco segundos.", "pt"),
|
||||
("Havia 50 soldados.", "Havia cinquenta soldados.", "pt"),
|
||||
@@ -761,8 +821,16 @@ def test_expand_numbers_multilingual():
|
||||
# Polish
|
||||
("W 12,5 sekundy.", "W dwanaście przecinek pięć sekundy.", "pl"),
|
||||
("Było 50 żołnierzy.", "Było pięćdziesiąt żołnierzy.", "pl"),
|
||||
("To będzie kosztować 20€ panie.", "To będzie kosztować dwadzieścia euro panie.", "pl"),
|
||||
("To będzie kosztować 20,15€ panie.", "To będzie kosztować dwadzieścia euro, piętnaście centów panie.", "pl"),
|
||||
(
|
||||
"To będzie kosztować 20€ panie.",
|
||||
"To będzie kosztować dwadzieścia euro panie.",
|
||||
"pl",
|
||||
),
|
||||
(
|
||||
"To będzie kosztować 20,15€ panie.",
|
||||
"To będzie kosztować dwadzieścia euro, piętnaście centów panie.",
|
||||
"pl",
|
||||
),
|
||||
# Arabic
|
||||
("في الـ 12,5 ثانية.", "في الـ اثنا عشر , خمسون ثانية.", "ar"),
|
||||
("كان هناك 50 جنديًا.", "كان هناك خمسون جنديًا.", "ar"),
|
||||
@@ -776,8 +844,16 @@ def test_expand_numbers_multilingual():
|
||||
# Russian
|
||||
("Через 12.5 секунды.", "Через двенадцать запятая пять секунды.", "ru"),
|
||||
("Там было 50 солдат.", "Там было пятьдесят солдат.", "ru"),
|
||||
("Это будет 20.15€ сэр.", "Это будет двадцать евро, пятнадцать центов сэр.", "ru"),
|
||||
("Это будет стоить 20€ господин.", "Это будет стоить двадцать евро господин.", "ru"),
|
||||
(
|
||||
"Это будет 20.15€ сэр.",
|
||||
"Это будет двадцать евро, пятнадцать центов сэр.",
|
||||
"ru",
|
||||
),
|
||||
(
|
||||
"Это будет стоить 20€ господин.",
|
||||
"Это будет стоить двадцать евро господин.",
|
||||
"ru",
|
||||
),
|
||||
# Dutch
|
||||
("In 12,5 seconden.", "In twaalf komma vijf seconden.", "nl"),
|
||||
("Er waren 50 soldaten.", "Er waren vijftig soldaten.", "nl"),
|
||||
@@ -817,18 +893,30 @@ def test_abbreviations_multilingual():
|
||||
("La Dra. Martinez es muy buena.", "La doctora Martinez es muy buena.", "es"),
|
||||
# French
|
||||
("Bonjour Mr. Dupond.", "Bonjour monsieur Dupond.", "fr"),
|
||||
("Mme. Moreau est absente aujourd'hui.", "madame Moreau est absente aujourd'hui.", "fr"),
|
||||
(
|
||||
"Mme. Moreau est absente aujourd'hui.",
|
||||
"madame Moreau est absente aujourd'hui.",
|
||||
"fr",
|
||||
),
|
||||
# German
|
||||
("Frau Dr. Müller ist sehr klug.", "Frau doktor Müller ist sehr klug.", "de"),
|
||||
# Portuguese
|
||||
("Olá Sr. Silva.", "Olá senhor Silva.", "pt"),
|
||||
("Dra. Costa, você está disponível?", "doutora Costa, você está disponível?", "pt"),
|
||||
(
|
||||
"Dra. Costa, você está disponível?",
|
||||
"doutora Costa, você está disponível?",
|
||||
"pt",
|
||||
),
|
||||
# Italian
|
||||
("Buongiorno, Sig. Rossi.", "Buongiorno, signore Rossi.", "it"),
|
||||
# ("Sig.ra Bianchi, posso aiutarti?", 'signora Bianchi, posso aiutarti?', 'it'), # Issue with matching that pattern
|
||||
# Polish
|
||||
("Dzień dobry, P. Kowalski.", "Dzień dobry, pani Kowalski.", "pl"),
|
||||
("M. Nowak, czy mogę zadać pytanie?", "pan Nowak, czy mogę zadać pytanie?", "pl"),
|
||||
(
|
||||
"M. Nowak, czy mogę zadać pytanie?",
|
||||
"pan Nowak, czy mogę zadać pytanie?",
|
||||
"pl",
|
||||
),
|
||||
# Czech
|
||||
("P. Novák", "pan Novák", "cs"),
|
||||
("Dr. Vojtěch", "doktor Vojtěch", "cs"),
|
||||
@@ -837,7 +925,11 @@ def test_abbreviations_multilingual():
|
||||
("Mevr. de Vries", "mevrouw de Vries", "nl"),
|
||||
# Russian
|
||||
("Здравствуйте Г-н Иванов.", "Здравствуйте господин Иванов.", "ru"),
|
||||
("Д-р Смирнов здесь, чтобы увидеть вас.", "доктор Смирнов здесь, чтобы увидеть вас.", "ru"),
|
||||
(
|
||||
"Д-р Смирнов здесь, чтобы увидеть вас.",
|
||||
"доктор Смирнов здесь, чтобы увидеть вас.",
|
||||
"ru",
|
||||
),
|
||||
# Turkish
|
||||
("Merhaba B. Yılmaz.", "Merhaba bay Yılmaz.", "tr"),
|
||||
("Dr. Ayşe burada.", "doktor Ayşe burada.", "tr"),
|
||||
@@ -856,8 +948,16 @@ def test_symbols_multilingual():
|
||||
("Te veo @ la fiesta", "Te veo arroba la fiesta", "es"),
|
||||
("J'ai 14° de fièvre", "J'ai 14 degrés de fièvre", "fr"),
|
||||
("Die Rechnung beträgt £ 20", "Die Rechnung beträgt pfund 20", "de"),
|
||||
("O meu email é ana&joao@gmail.com", "O meu email é ana e joao arroba gmail.com", "pt"),
|
||||
("linguaggio di programmazione C#", "linguaggio di programmazione C cancelletto", "it"),
|
||||
(
|
||||
"O meu email é ana&joao@gmail.com",
|
||||
"O meu email é ana e joao arroba gmail.com",
|
||||
"pt",
|
||||
),
|
||||
(
|
||||
"linguaggio di programmazione C#",
|
||||
"linguaggio di programmazione C cancelletto",
|
||||
"it",
|
||||
),
|
||||
("Moja temperatura to 36.6°", "Moja temperatura to 36.6 stopnie", "pl"),
|
||||
("Mám 14% baterie", "Mám 14 procento baterie", "cs"),
|
||||
("Těším se na tebe @ party", "Těším se na tebe na party", "cs"),
|
||||
@@ -868,7 +968,11 @@ def test_symbols_multilingual():
|
||||
("لدي 14% في البطارية", "لدي 14 في المئة في البطارية", "ar"),
|
||||
("我的电量为 14%", "我的电量为 14 百分之", "zh"),
|
||||
("Pilim %14 dolu.", "Pilim yüzde 14 dolu.", "tr"),
|
||||
("Az akkumulátorom töltöttsége 14%", "Az akkumulátorom töltöttsége 14 százalék", "hu"),
|
||||
(
|
||||
"Az akkumulátorom töltöttsége 14%",
|
||||
"Az akkumulátorom töltöttsége 14 százalék",
|
||||
"hu",
|
||||
),
|
||||
("배터리 잔량이 14%입니다.", "배터리 잔량이 14 퍼센트입니다.", "ko"),
|
||||
]
|
||||
|
||||
@@ -880,4 +984,4 @@ def test_symbols_multilingual():
|
||||
if __name__ == "__main__":
|
||||
test_expand_numbers_multilingual()
|
||||
test_abbreviations_multilingual()
|
||||
test_symbols_multilingual()
|
||||
test_symbols_multilingual()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Authors:
|
||||
# 2019.5 Zhiyang Zhou (https://github.com/Joee1995/chn_text_norm.git)
|
||||
# 2019.9 - 2022 Jiayu DU
|
||||
#copy from https://github.com/coqui-ai/TTS/blob/dbf1a08a0d4e47fdad6172e433eeb34bc6b13b4e/TTS/tts/layers/xtts/zh_num2words.py
|
||||
# copy from https://github.com/coqui-ai/TTS/blob/dbf1a08a0d4e47fdad6172e433eeb34bc6b13b4e/TTS/tts/layers/xtts/zh_num2words.py
|
||||
import argparse
|
||||
import csv
|
||||
import os
|
||||
@@ -1206,4 +1206,4 @@ if __name__ == "__main__":
|
||||
ndone += 1
|
||||
if ndone % args.log_interval == 0:
|
||||
print(f"text norm: {ndone} lines done.", file=sys.stderr, flush=True)
|
||||
print(f"text norm: {ndone} lines done in total.", file=sys.stderr, flush=True)
|
||||
print(f"text norm: {ndone} lines done in total.", file=sys.stderr, flush=True)
|
||||
|
||||
Reference in New Issue
Block a user