ElesisSiegherts
commited on
Commit
•
8900345
1
Parent(s):
229f0e6
Upload 6 files
Browse files- attentions.py +464 -0
- attentions_onnx.py +378 -0
- bert_gen.py +74 -0
- commons.py +166 -0
- compress_model.py +88 -0
- config.py +244 -0
attentions.py
ADDED
@@ -0,0 +1,464 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import math
|
2 |
+
import torch
|
3 |
+
from torch import nn
|
4 |
+
from torch.nn import functional as F
|
5 |
+
|
6 |
+
import commons
|
7 |
+
import logging
|
8 |
+
|
9 |
+
logger = logging.getLogger(__name__)
|
10 |
+
|
11 |
+
|
12 |
+
class LayerNorm(nn.Module):
|
13 |
+
def __init__(self, channels, eps=1e-5):
|
14 |
+
super().__init__()
|
15 |
+
self.channels = channels
|
16 |
+
self.eps = eps
|
17 |
+
|
18 |
+
self.gamma = nn.Parameter(torch.ones(channels))
|
19 |
+
self.beta = nn.Parameter(torch.zeros(channels))
|
20 |
+
|
21 |
+
def forward(self, x):
|
22 |
+
x = x.transpose(1, -1)
|
23 |
+
x = F.layer_norm(x, (self.channels,), self.gamma, self.beta, self.eps)
|
24 |
+
return x.transpose(1, -1)
|
25 |
+
|
26 |
+
|
27 |
+
@torch.jit.script
|
28 |
+
def fused_add_tanh_sigmoid_multiply(input_a, input_b, n_channels):
|
29 |
+
n_channels_int = n_channels[0]
|
30 |
+
in_act = input_a + input_b
|
31 |
+
t_act = torch.tanh(in_act[:, :n_channels_int, :])
|
32 |
+
s_act = torch.sigmoid(in_act[:, n_channels_int:, :])
|
33 |
+
acts = t_act * s_act
|
34 |
+
return acts
|
35 |
+
|
36 |
+
|
37 |
+
class Encoder(nn.Module):
|
38 |
+
def __init__(
|
39 |
+
self,
|
40 |
+
hidden_channels,
|
41 |
+
filter_channels,
|
42 |
+
n_heads,
|
43 |
+
n_layers,
|
44 |
+
kernel_size=1,
|
45 |
+
p_dropout=0.0,
|
46 |
+
window_size=4,
|
47 |
+
isflow=True,
|
48 |
+
**kwargs
|
49 |
+
):
|
50 |
+
super().__init__()
|
51 |
+
self.hidden_channels = hidden_channels
|
52 |
+
self.filter_channels = filter_channels
|
53 |
+
self.n_heads = n_heads
|
54 |
+
self.n_layers = n_layers
|
55 |
+
self.kernel_size = kernel_size
|
56 |
+
self.p_dropout = p_dropout
|
57 |
+
self.window_size = window_size
|
58 |
+
# if isflow:
|
59 |
+
# cond_layer = torch.nn.Conv1d(256, 2*hidden_channels*n_layers, 1)
|
60 |
+
# self.cond_pre = torch.nn.Conv1d(hidden_channels, 2*hidden_channels, 1)
|
61 |
+
# self.cond_layer = weight_norm(cond_layer, name='weight')
|
62 |
+
# self.gin_channels = 256
|
63 |
+
self.cond_layer_idx = self.n_layers
|
64 |
+
if "gin_channels" in kwargs:
|
65 |
+
self.gin_channels = kwargs["gin_channels"]
|
66 |
+
if self.gin_channels != 0:
|
67 |
+
self.spk_emb_linear = nn.Linear(self.gin_channels, self.hidden_channels)
|
68 |
+
# vits2 says 3rd block, so idx is 2 by default
|
69 |
+
self.cond_layer_idx = (
|
70 |
+
kwargs["cond_layer_idx"] if "cond_layer_idx" in kwargs else 2
|
71 |
+
)
|
72 |
+
logging.debug(self.gin_channels, self.cond_layer_idx)
|
73 |
+
assert (
|
74 |
+
self.cond_layer_idx < self.n_layers
|
75 |
+
), "cond_layer_idx should be less than n_layers"
|
76 |
+
self.drop = nn.Dropout(p_dropout)
|
77 |
+
self.attn_layers = nn.ModuleList()
|
78 |
+
self.norm_layers_1 = nn.ModuleList()
|
79 |
+
self.ffn_layers = nn.ModuleList()
|
80 |
+
self.norm_layers_2 = nn.ModuleList()
|
81 |
+
for i in range(self.n_layers):
|
82 |
+
self.attn_layers.append(
|
83 |
+
MultiHeadAttention(
|
84 |
+
hidden_channels,
|
85 |
+
hidden_channels,
|
86 |
+
n_heads,
|
87 |
+
p_dropout=p_dropout,
|
88 |
+
window_size=window_size,
|
89 |
+
)
|
90 |
+
)
|
91 |
+
self.norm_layers_1.append(LayerNorm(hidden_channels))
|
92 |
+
self.ffn_layers.append(
|
93 |
+
FFN(
|
94 |
+
hidden_channels,
|
95 |
+
hidden_channels,
|
96 |
+
filter_channels,
|
97 |
+
kernel_size,
|
98 |
+
p_dropout=p_dropout,
|
99 |
+
)
|
100 |
+
)
|
101 |
+
self.norm_layers_2.append(LayerNorm(hidden_channels))
|
102 |
+
|
103 |
+
def forward(self, x, x_mask, g=None):
|
104 |
+
attn_mask = x_mask.unsqueeze(2) * x_mask.unsqueeze(-1)
|
105 |
+
x = x * x_mask
|
106 |
+
for i in range(self.n_layers):
|
107 |
+
if i == self.cond_layer_idx and g is not None:
|
108 |
+
g = self.spk_emb_linear(g.transpose(1, 2))
|
109 |
+
g = g.transpose(1, 2)
|
110 |
+
x = x + g
|
111 |
+
x = x * x_mask
|
112 |
+
y = self.attn_layers[i](x, x, attn_mask)
|
113 |
+
y = self.drop(y)
|
114 |
+
x = self.norm_layers_1[i](x + y)
|
115 |
+
|
116 |
+
y = self.ffn_layers[i](x, x_mask)
|
117 |
+
y = self.drop(y)
|
118 |
+
x = self.norm_layers_2[i](x + y)
|
119 |
+
x = x * x_mask
|
120 |
+
return x
|
121 |
+
|
122 |
+
|
123 |
+
class Decoder(nn.Module):
|
124 |
+
def __init__(
|
125 |
+
self,
|
126 |
+
hidden_channels,
|
127 |
+
filter_channels,
|
128 |
+
n_heads,
|
129 |
+
n_layers,
|
130 |
+
kernel_size=1,
|
131 |
+
p_dropout=0.0,
|
132 |
+
proximal_bias=False,
|
133 |
+
proximal_init=True,
|
134 |
+
**kwargs
|
135 |
+
):
|
136 |
+
super().__init__()
|
137 |
+
self.hidden_channels = hidden_channels
|
138 |
+
self.filter_channels = filter_channels
|
139 |
+
self.n_heads = n_heads
|
140 |
+
self.n_layers = n_layers
|
141 |
+
self.kernel_size = kernel_size
|
142 |
+
self.p_dropout = p_dropout
|
143 |
+
self.proximal_bias = proximal_bias
|
144 |
+
self.proximal_init = proximal_init
|
145 |
+
|
146 |
+
self.drop = nn.Dropout(p_dropout)
|
147 |
+
self.self_attn_layers = nn.ModuleList()
|
148 |
+
self.norm_layers_0 = nn.ModuleList()
|
149 |
+
self.encdec_attn_layers = nn.ModuleList()
|
150 |
+
self.norm_layers_1 = nn.ModuleList()
|
151 |
+
self.ffn_layers = nn.ModuleList()
|
152 |
+
self.norm_layers_2 = nn.ModuleList()
|
153 |
+
for i in range(self.n_layers):
|
154 |
+
self.self_attn_layers.append(
|
155 |
+
MultiHeadAttention(
|
156 |
+
hidden_channels,
|
157 |
+
hidden_channels,
|
158 |
+
n_heads,
|
159 |
+
p_dropout=p_dropout,
|
160 |
+
proximal_bias=proximal_bias,
|
161 |
+
proximal_init=proximal_init,
|
162 |
+
)
|
163 |
+
)
|
164 |
+
self.norm_layers_0.append(LayerNorm(hidden_channels))
|
165 |
+
self.encdec_attn_layers.append(
|
166 |
+
MultiHeadAttention(
|
167 |
+
hidden_channels, hidden_channels, n_heads, p_dropout=p_dropout
|
168 |
+
)
|
169 |
+
)
|
170 |
+
self.norm_layers_1.append(LayerNorm(hidden_channels))
|
171 |
+
self.ffn_layers.append(
|
172 |
+
FFN(
|
173 |
+
hidden_channels,
|
174 |
+
hidden_channels,
|
175 |
+
filter_channels,
|
176 |
+
kernel_size,
|
177 |
+
p_dropout=p_dropout,
|
178 |
+
causal=True,
|
179 |
+
)
|
180 |
+
)
|
181 |
+
self.norm_layers_2.append(LayerNorm(hidden_channels))
|
182 |
+
|
183 |
+
def forward(self, x, x_mask, h, h_mask):
|
184 |
+
"""
|
185 |
+
x: decoder input
|
186 |
+
h: encoder output
|
187 |
+
"""
|
188 |
+
self_attn_mask = commons.subsequent_mask(x_mask.size(2)).to(
|
189 |
+
device=x.device, dtype=x.dtype
|
190 |
+
)
|
191 |
+
encdec_attn_mask = h_mask.unsqueeze(2) * x_mask.unsqueeze(-1)
|
192 |
+
x = x * x_mask
|
193 |
+
for i in range(self.n_layers):
|
194 |
+
y = self.self_attn_layers[i](x, x, self_attn_mask)
|
195 |
+
y = self.drop(y)
|
196 |
+
x = self.norm_layers_0[i](x + y)
|
197 |
+
|
198 |
+
y = self.encdec_attn_layers[i](x, h, encdec_attn_mask)
|
199 |
+
y = self.drop(y)
|
200 |
+
x = self.norm_layers_1[i](x + y)
|
201 |
+
|
202 |
+
y = self.ffn_layers[i](x, x_mask)
|
203 |
+
y = self.drop(y)
|
204 |
+
x = self.norm_layers_2[i](x + y)
|
205 |
+
x = x * x_mask
|
206 |
+
return x
|
207 |
+
|
208 |
+
|
209 |
+
class MultiHeadAttention(nn.Module):
|
210 |
+
def __init__(
|
211 |
+
self,
|
212 |
+
channels,
|
213 |
+
out_channels,
|
214 |
+
n_heads,
|
215 |
+
p_dropout=0.0,
|
216 |
+
window_size=None,
|
217 |
+
heads_share=True,
|
218 |
+
block_length=None,
|
219 |
+
proximal_bias=False,
|
220 |
+
proximal_init=False,
|
221 |
+
):
|
222 |
+
super().__init__()
|
223 |
+
assert channels % n_heads == 0
|
224 |
+
|
225 |
+
self.channels = channels
|
226 |
+
self.out_channels = out_channels
|
227 |
+
self.n_heads = n_heads
|
228 |
+
self.p_dropout = p_dropout
|
229 |
+
self.window_size = window_size
|
230 |
+
self.heads_share = heads_share
|
231 |
+
self.block_length = block_length
|
232 |
+
self.proximal_bias = proximal_bias
|
233 |
+
self.proximal_init = proximal_init
|
234 |
+
self.attn = None
|
235 |
+
|
236 |
+
self.k_channels = channels // n_heads
|
237 |
+
self.conv_q = nn.Conv1d(channels, channels, 1)
|
238 |
+
self.conv_k = nn.Conv1d(channels, channels, 1)
|
239 |
+
self.conv_v = nn.Conv1d(channels, channels, 1)
|
240 |
+
self.conv_o = nn.Conv1d(channels, out_channels, 1)
|
241 |
+
self.drop = nn.Dropout(p_dropout)
|
242 |
+
|
243 |
+
if window_size is not None:
|
244 |
+
n_heads_rel = 1 if heads_share else n_heads
|
245 |
+
rel_stddev = self.k_channels**-0.5
|
246 |
+
self.emb_rel_k = nn.Parameter(
|
247 |
+
torch.randn(n_heads_rel, window_size * 2 + 1, self.k_channels)
|
248 |
+
* rel_stddev
|
249 |
+
)
|
250 |
+
self.emb_rel_v = nn.Parameter(
|
251 |
+
torch.randn(n_heads_rel, window_size * 2 + 1, self.k_channels)
|
252 |
+
* rel_stddev
|
253 |
+
)
|
254 |
+
|
255 |
+
nn.init.xavier_uniform_(self.conv_q.weight)
|
256 |
+
nn.init.xavier_uniform_(self.conv_k.weight)
|
257 |
+
nn.init.xavier_uniform_(self.conv_v.weight)
|
258 |
+
if proximal_init:
|
259 |
+
with torch.no_grad():
|
260 |
+
self.conv_k.weight.copy_(self.conv_q.weight)
|
261 |
+
self.conv_k.bias.copy_(self.conv_q.bias)
|
262 |
+
|
263 |
+
def forward(self, x, c, attn_mask=None):
|
264 |
+
q = self.conv_q(x)
|
265 |
+
k = self.conv_k(c)
|
266 |
+
v = self.conv_v(c)
|
267 |
+
|
268 |
+
x, self.attn = self.attention(q, k, v, mask=attn_mask)
|
269 |
+
|
270 |
+
x = self.conv_o(x)
|
271 |
+
return x
|
272 |
+
|
273 |
+
def attention(self, query, key, value, mask=None):
|
274 |
+
# reshape [b, d, t] -> [b, n_h, t, d_k]
|
275 |
+
b, d, t_s, t_t = (*key.size(), query.size(2))
|
276 |
+
query = query.view(b, self.n_heads, self.k_channels, t_t).transpose(2, 3)
|
277 |
+
key = key.view(b, self.n_heads, self.k_channels, t_s).transpose(2, 3)
|
278 |
+
value = value.view(b, self.n_heads, self.k_channels, t_s).transpose(2, 3)
|
279 |
+
|
280 |
+
scores = torch.matmul(query / math.sqrt(self.k_channels), key.transpose(-2, -1))
|
281 |
+
if self.window_size is not None:
|
282 |
+
assert (
|
283 |
+
t_s == t_t
|
284 |
+
), "Relative attention is only available for self-attention."
|
285 |
+
key_relative_embeddings = self._get_relative_embeddings(self.emb_rel_k, t_s)
|
286 |
+
rel_logits = self._matmul_with_relative_keys(
|
287 |
+
query / math.sqrt(self.k_channels), key_relative_embeddings
|
288 |
+
)
|
289 |
+
scores_local = self._relative_position_to_absolute_position(rel_logits)
|
290 |
+
scores = scores + scores_local
|
291 |
+
if self.proximal_bias:
|
292 |
+
assert t_s == t_t, "Proximal bias is only available for self-attention."
|
293 |
+
scores = scores + self._attention_bias_proximal(t_s).to(
|
294 |
+
device=scores.device, dtype=scores.dtype
|
295 |
+
)
|
296 |
+
if mask is not None:
|
297 |
+
scores = scores.masked_fill(mask == 0, -1e4)
|
298 |
+
if self.block_length is not None:
|
299 |
+
assert (
|
300 |
+
t_s == t_t
|
301 |
+
), "Local attention is only available for self-attention."
|
302 |
+
block_mask = (
|
303 |
+
torch.ones_like(scores)
|
304 |
+
.triu(-self.block_length)
|
305 |
+
.tril(self.block_length)
|
306 |
+
)
|
307 |
+
scores = scores.masked_fill(block_mask == 0, -1e4)
|
308 |
+
p_attn = F.softmax(scores, dim=-1) # [b, n_h, t_t, t_s]
|
309 |
+
p_attn = self.drop(p_attn)
|
310 |
+
output = torch.matmul(p_attn, value)
|
311 |
+
if self.window_size is not None:
|
312 |
+
relative_weights = self._absolute_position_to_relative_position(p_attn)
|
313 |
+
value_relative_embeddings = self._get_relative_embeddings(
|
314 |
+
self.emb_rel_v, t_s
|
315 |
+
)
|
316 |
+
output = output + self._matmul_with_relative_values(
|
317 |
+
relative_weights, value_relative_embeddings
|
318 |
+
)
|
319 |
+
output = (
|
320 |
+
output.transpose(2, 3).contiguous().view(b, d, t_t)
|
321 |
+
) # [b, n_h, t_t, d_k] -> [b, d, t_t]
|
322 |
+
return output, p_attn
|
323 |
+
|
324 |
+
def _matmul_with_relative_values(self, x, y):
|
325 |
+
"""
|
326 |
+
x: [b, h, l, m]
|
327 |
+
y: [h or 1, m, d]
|
328 |
+
ret: [b, h, l, d]
|
329 |
+
"""
|
330 |
+
ret = torch.matmul(x, y.unsqueeze(0))
|
331 |
+
return ret
|
332 |
+
|
333 |
+
def _matmul_with_relative_keys(self, x, y):
|
334 |
+
"""
|
335 |
+
x: [b, h, l, d]
|
336 |
+
y: [h or 1, m, d]
|
337 |
+
ret: [b, h, l, m]
|
338 |
+
"""
|
339 |
+
ret = torch.matmul(x, y.unsqueeze(0).transpose(-2, -1))
|
340 |
+
return ret
|
341 |
+
|
342 |
+
def _get_relative_embeddings(self, relative_embeddings, length):
|
343 |
+
2 * self.window_size + 1
|
344 |
+
# Pad first before slice to avoid using cond ops.
|
345 |
+
pad_length = max(length - (self.window_size + 1), 0)
|
346 |
+
slice_start_position = max((self.window_size + 1) - length, 0)
|
347 |
+
slice_end_position = slice_start_position + 2 * length - 1
|
348 |
+
if pad_length > 0:
|
349 |
+
padded_relative_embeddings = F.pad(
|
350 |
+
relative_embeddings,
|
351 |
+
commons.convert_pad_shape([[0, 0], [pad_length, pad_length], [0, 0]]),
|
352 |
+
)
|
353 |
+
else:
|
354 |
+
padded_relative_embeddings = relative_embeddings
|
355 |
+
used_relative_embeddings = padded_relative_embeddings[
|
356 |
+
:, slice_start_position:slice_end_position
|
357 |
+
]
|
358 |
+
return used_relative_embeddings
|
359 |
+
|
360 |
+
def _relative_position_to_absolute_position(self, x):
|
361 |
+
"""
|
362 |
+
x: [b, h, l, 2*l-1]
|
363 |
+
ret: [b, h, l, l]
|
364 |
+
"""
|
365 |
+
batch, heads, length, _ = x.size()
|
366 |
+
# Concat columns of pad to shift from relative to absolute indexing.
|
367 |
+
x = F.pad(x, commons.convert_pad_shape([[0, 0], [0, 0], [0, 0], [0, 1]]))
|
368 |
+
|
369 |
+
# Concat extra elements so to add up to shape (len+1, 2*len-1).
|
370 |
+
x_flat = x.view([batch, heads, length * 2 * length])
|
371 |
+
x_flat = F.pad(
|
372 |
+
x_flat, commons.convert_pad_shape([[0, 0], [0, 0], [0, length - 1]])
|
373 |
+
)
|
374 |
+
|
375 |
+
# Reshape and slice out the padded elements.
|
376 |
+
x_final = x_flat.view([batch, heads, length + 1, 2 * length - 1])[
|
377 |
+
:, :, :length, length - 1 :
|
378 |
+
]
|
379 |
+
return x_final
|
380 |
+
|
381 |
+
def _absolute_position_to_relative_position(self, x):
|
382 |
+
"""
|
383 |
+
x: [b, h, l, l]
|
384 |
+
ret: [b, h, l, 2*l-1]
|
385 |
+
"""
|
386 |
+
batch, heads, length, _ = x.size()
|
387 |
+
# pad along column
|
388 |
+
x = F.pad(
|
389 |
+
x, commons.convert_pad_shape([[0, 0], [0, 0], [0, 0], [0, length - 1]])
|
390 |
+
)
|
391 |
+
x_flat = x.view([batch, heads, length**2 + length * (length - 1)])
|
392 |
+
# add 0's in the beginning that will skew the elements after reshape
|
393 |
+
x_flat = F.pad(x_flat, commons.convert_pad_shape([[0, 0], [0, 0], [length, 0]]))
|
394 |
+
x_final = x_flat.view([batch, heads, length, 2 * length])[:, :, :, 1:]
|
395 |
+
return x_final
|
396 |
+
|
397 |
+
def _attention_bias_proximal(self, length):
|
398 |
+
"""Bias for self-attention to encourage attention to close positions.
|
399 |
+
Args:
|
400 |
+
length: an integer scalar.
|
401 |
+
Returns:
|
402 |
+
a Tensor with shape [1, 1, length, length]
|
403 |
+
"""
|
404 |
+
r = torch.arange(length, dtype=torch.float32)
|
405 |
+
diff = torch.unsqueeze(r, 0) - torch.unsqueeze(r, 1)
|
406 |
+
return torch.unsqueeze(torch.unsqueeze(-torch.log1p(torch.abs(diff)), 0), 0)
|
407 |
+
|
408 |
+
|
409 |
+
class FFN(nn.Module):
|
410 |
+
def __init__(
|
411 |
+
self,
|
412 |
+
in_channels,
|
413 |
+
out_channels,
|
414 |
+
filter_channels,
|
415 |
+
kernel_size,
|
416 |
+
p_dropout=0.0,
|
417 |
+
activation=None,
|
418 |
+
causal=False,
|
419 |
+
):
|
420 |
+
super().__init__()
|
421 |
+
self.in_channels = in_channels
|
422 |
+
self.out_channels = out_channels
|
423 |
+
self.filter_channels = filter_channels
|
424 |
+
self.kernel_size = kernel_size
|
425 |
+
self.p_dropout = p_dropout
|
426 |
+
self.activation = activation
|
427 |
+
self.causal = causal
|
428 |
+
|
429 |
+
if causal:
|
430 |
+
self.padding = self._causal_padding
|
431 |
+
else:
|
432 |
+
self.padding = self._same_padding
|
433 |
+
|
434 |
+
self.conv_1 = nn.Conv1d(in_channels, filter_channels, kernel_size)
|
435 |
+
self.conv_2 = nn.Conv1d(filter_channels, out_channels, kernel_size)
|
436 |
+
self.drop = nn.Dropout(p_dropout)
|
437 |
+
|
438 |
+
def forward(self, x, x_mask):
|
439 |
+
x = self.conv_1(self.padding(x * x_mask))
|
440 |
+
if self.activation == "gelu":
|
441 |
+
x = x * torch.sigmoid(1.702 * x)
|
442 |
+
else:
|
443 |
+
x = torch.relu(x)
|
444 |
+
x = self.drop(x)
|
445 |
+
x = self.conv_2(self.padding(x * x_mask))
|
446 |
+
return x * x_mask
|
447 |
+
|
448 |
+
def _causal_padding(self, x):
|
449 |
+
if self.kernel_size == 1:
|
450 |
+
return x
|
451 |
+
pad_l = self.kernel_size - 1
|
452 |
+
pad_r = 0
|
453 |
+
padding = [[0, 0], [0, 0], [pad_l, pad_r]]
|
454 |
+
x = F.pad(x, commons.convert_pad_shape(padding))
|
455 |
+
return x
|
456 |
+
|
457 |
+
def _same_padding(self, x):
|
458 |
+
if self.kernel_size == 1:
|
459 |
+
return x
|
460 |
+
pad_l = (self.kernel_size - 1) // 2
|
461 |
+
pad_r = self.kernel_size // 2
|
462 |
+
padding = [[0, 0], [0, 0], [pad_l, pad_r]]
|
463 |
+
x = F.pad(x, commons.convert_pad_shape(padding))
|
464 |
+
return x
|
attentions_onnx.py
ADDED
@@ -0,0 +1,378 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import math
|
2 |
+
import torch
|
3 |
+
from torch import nn
|
4 |
+
from torch.nn import functional as F
|
5 |
+
|
6 |
+
import commons
|
7 |
+
import logging
|
8 |
+
|
9 |
+
logger = logging.getLogger(__name__)
|
10 |
+
|
11 |
+
|
12 |
+
class LayerNorm(nn.Module):
|
13 |
+
def __init__(self, channels, eps=1e-5):
|
14 |
+
super().__init__()
|
15 |
+
self.channels = channels
|
16 |
+
self.eps = eps
|
17 |
+
|
18 |
+
self.gamma = nn.Parameter(torch.ones(channels))
|
19 |
+
self.beta = nn.Parameter(torch.zeros(channels))
|
20 |
+
|
21 |
+
def forward(self, x):
|
22 |
+
x = x.transpose(1, -1)
|
23 |
+
x = F.layer_norm(x, (self.channels,), self.gamma, self.beta, self.eps)
|
24 |
+
return x.transpose(1, -1)
|
25 |
+
|
26 |
+
|
27 |
+
@torch.jit.script
|
28 |
+
def fused_add_tanh_sigmoid_multiply(input_a, input_b, n_channels):
|
29 |
+
n_channels_int = n_channels[0]
|
30 |
+
in_act = input_a + input_b
|
31 |
+
t_act = torch.tanh(in_act[:, :n_channels_int, :])
|
32 |
+
s_act = torch.sigmoid(in_act[:, n_channels_int:, :])
|
33 |
+
acts = t_act * s_act
|
34 |
+
return acts
|
35 |
+
|
36 |
+
|
37 |
+
class Encoder(nn.Module):
|
38 |
+
def __init__(
|
39 |
+
self,
|
40 |
+
hidden_channels,
|
41 |
+
filter_channels,
|
42 |
+
n_heads,
|
43 |
+
n_layers,
|
44 |
+
kernel_size=1,
|
45 |
+
p_dropout=0.0,
|
46 |
+
window_size=4,
|
47 |
+
isflow=True,
|
48 |
+
**kwargs
|
49 |
+
):
|
50 |
+
super().__init__()
|
51 |
+
self.hidden_channels = hidden_channels
|
52 |
+
self.filter_channels = filter_channels
|
53 |
+
self.n_heads = n_heads
|
54 |
+
self.n_layers = n_layers
|
55 |
+
self.kernel_size = kernel_size
|
56 |
+
self.p_dropout = p_dropout
|
57 |
+
self.window_size = window_size
|
58 |
+
# if isflow:
|
59 |
+
# cond_layer = torch.nn.Conv1d(256, 2*hidden_channels*n_layers, 1)
|
60 |
+
# self.cond_pre = torch.nn.Conv1d(hidden_channels, 2*hidden_channels, 1)
|
61 |
+
# self.cond_layer = weight_norm(cond_layer, name='weight')
|
62 |
+
# self.gin_channels = 256
|
63 |
+
self.cond_layer_idx = self.n_layers
|
64 |
+
if "gin_channels" in kwargs:
|
65 |
+
self.gin_channels = kwargs["gin_channels"]
|
66 |
+
if self.gin_channels != 0:
|
67 |
+
self.spk_emb_linear = nn.Linear(self.gin_channels, self.hidden_channels)
|
68 |
+
# vits2 says 3rd block, so idx is 2 by default
|
69 |
+
self.cond_layer_idx = (
|
70 |
+
kwargs["cond_layer_idx"] if "cond_layer_idx" in kwargs else 2
|
71 |
+
)
|
72 |
+
logging.debug(self.gin_channels, self.cond_layer_idx)
|
73 |
+
assert (
|
74 |
+
self.cond_layer_idx < self.n_layers
|
75 |
+
), "cond_layer_idx should be less than n_layers"
|
76 |
+
self.drop = nn.Dropout(p_dropout)
|
77 |
+
self.attn_layers = nn.ModuleList()
|
78 |
+
self.norm_layers_1 = nn.ModuleList()
|
79 |
+
self.ffn_layers = nn.ModuleList()
|
80 |
+
self.norm_layers_2 = nn.ModuleList()
|
81 |
+
for i in range(self.n_layers):
|
82 |
+
self.attn_layers.append(
|
83 |
+
MultiHeadAttention(
|
84 |
+
hidden_channels,
|
85 |
+
hidden_channels,
|
86 |
+
n_heads,
|
87 |
+
p_dropout=p_dropout,
|
88 |
+
window_size=window_size,
|
89 |
+
)
|
90 |
+
)
|
91 |
+
self.norm_layers_1.append(LayerNorm(hidden_channels))
|
92 |
+
self.ffn_layers.append(
|
93 |
+
FFN(
|
94 |
+
hidden_channels,
|
95 |
+
hidden_channels,
|
96 |
+
filter_channels,
|
97 |
+
kernel_size,
|
98 |
+
p_dropout=p_dropout,
|
99 |
+
)
|
100 |
+
)
|
101 |
+
self.norm_layers_2.append(LayerNorm(hidden_channels))
|
102 |
+
|
103 |
+
def forward(self, x, x_mask, g=None):
|
104 |
+
attn_mask = x_mask.unsqueeze(2) * x_mask.unsqueeze(-1)
|
105 |
+
x = x * x_mask
|
106 |
+
for i in range(self.n_layers):
|
107 |
+
if i == self.cond_layer_idx and g is not None:
|
108 |
+
g = self.spk_emb_linear(g.transpose(1, 2))
|
109 |
+
g = g.transpose(1, 2)
|
110 |
+
x = x + g
|
111 |
+
x = x * x_mask
|
112 |
+
y = self.attn_layers[i](x, x, attn_mask)
|
113 |
+
y = self.drop(y)
|
114 |
+
x = self.norm_layers_1[i](x + y)
|
115 |
+
|
116 |
+
y = self.ffn_layers[i](x, x_mask)
|
117 |
+
y = self.drop(y)
|
118 |
+
x = self.norm_layers_2[i](x + y)
|
119 |
+
x = x * x_mask
|
120 |
+
return x
|
121 |
+
|
122 |
+
|
123 |
+
class MultiHeadAttention(nn.Module):
|
124 |
+
def __init__(
|
125 |
+
self,
|
126 |
+
channels,
|
127 |
+
out_channels,
|
128 |
+
n_heads,
|
129 |
+
p_dropout=0.0,
|
130 |
+
window_size=None,
|
131 |
+
heads_share=True,
|
132 |
+
block_length=None,
|
133 |
+
proximal_bias=False,
|
134 |
+
proximal_init=False,
|
135 |
+
):
|
136 |
+
super().__init__()
|
137 |
+
assert channels % n_heads == 0
|
138 |
+
|
139 |
+
self.channels = channels
|
140 |
+
self.out_channels = out_channels
|
141 |
+
self.n_heads = n_heads
|
142 |
+
self.p_dropout = p_dropout
|
143 |
+
self.window_size = window_size
|
144 |
+
self.heads_share = heads_share
|
145 |
+
self.block_length = block_length
|
146 |
+
self.proximal_bias = proximal_bias
|
147 |
+
self.proximal_init = proximal_init
|
148 |
+
self.attn = None
|
149 |
+
|
150 |
+
self.k_channels = channels // n_heads
|
151 |
+
self.conv_q = nn.Conv1d(channels, channels, 1)
|
152 |
+
self.conv_k = nn.Conv1d(channels, channels, 1)
|
153 |
+
self.conv_v = nn.Conv1d(channels, channels, 1)
|
154 |
+
self.conv_o = nn.Conv1d(channels, out_channels, 1)
|
155 |
+
self.drop = nn.Dropout(p_dropout)
|
156 |
+
|
157 |
+
if window_size is not None:
|
158 |
+
n_heads_rel = 1 if heads_share else n_heads
|
159 |
+
rel_stddev = self.k_channels**-0.5
|
160 |
+
self.emb_rel_k = nn.Parameter(
|
161 |
+
torch.randn(n_heads_rel, window_size * 2 + 1, self.k_channels)
|
162 |
+
* rel_stddev
|
163 |
+
)
|
164 |
+
self.emb_rel_v = nn.Parameter(
|
165 |
+
torch.randn(n_heads_rel, window_size * 2 + 1, self.k_channels)
|
166 |
+
* rel_stddev
|
167 |
+
)
|
168 |
+
|
169 |
+
nn.init.xavier_uniform_(self.conv_q.weight)
|
170 |
+
nn.init.xavier_uniform_(self.conv_k.weight)
|
171 |
+
nn.init.xavier_uniform_(self.conv_v.weight)
|
172 |
+
if proximal_init:
|
173 |
+
with torch.no_grad():
|
174 |
+
self.conv_k.weight.copy_(self.conv_q.weight)
|
175 |
+
self.conv_k.bias.copy_(self.conv_q.bias)
|
176 |
+
|
177 |
+
def forward(self, x, c, attn_mask=None):
|
178 |
+
q = self.conv_q(x)
|
179 |
+
k = self.conv_k(c)
|
180 |
+
v = self.conv_v(c)
|
181 |
+
|
182 |
+
x, self.attn = self.attention(q, k, v, mask=attn_mask)
|
183 |
+
|
184 |
+
x = self.conv_o(x)
|
185 |
+
return x
|
186 |
+
|
187 |
+
def attention(self, query, key, value, mask=None):
|
188 |
+
# reshape [b, d, t] -> [b, n_h, t, d_k]
|
189 |
+
b, d, t_s, t_t = (*key.size(), query.size(2))
|
190 |
+
query = query.view(b, self.n_heads, self.k_channels, t_t).transpose(2, 3)
|
191 |
+
key = key.view(b, self.n_heads, self.k_channels, t_s).transpose(2, 3)
|
192 |
+
value = value.view(b, self.n_heads, self.k_channels, t_s).transpose(2, 3)
|
193 |
+
|
194 |
+
scores = torch.matmul(query / math.sqrt(self.k_channels), key.transpose(-2, -1))
|
195 |
+
if self.window_size is not None:
|
196 |
+
assert (
|
197 |
+
t_s == t_t
|
198 |
+
), "Relative attention is only available for self-attention."
|
199 |
+
key_relative_embeddings = self._get_relative_embeddings(self.emb_rel_k, t_s)
|
200 |
+
rel_logits = self._matmul_with_relative_keys(
|
201 |
+
query / math.sqrt(self.k_channels), key_relative_embeddings
|
202 |
+
)
|
203 |
+
scores_local = self._relative_position_to_absolute_position(rel_logits)
|
204 |
+
scores = scores + scores_local
|
205 |
+
if self.proximal_bias:
|
206 |
+
assert t_s == t_t, "Proximal bias is only available for self-attention."
|
207 |
+
scores = scores + self._attention_bias_proximal(t_s).to(
|
208 |
+
device=scores.device, dtype=scores.dtype
|
209 |
+
)
|
210 |
+
if mask is not None:
|
211 |
+
scores = scores.masked_fill(mask == 0, -1e4)
|
212 |
+
if self.block_length is not None:
|
213 |
+
assert (
|
214 |
+
t_s == t_t
|
215 |
+
), "Local attention is only available for self-attention."
|
216 |
+
block_mask = (
|
217 |
+
torch.ones_like(scores)
|
218 |
+
.triu(-self.block_length)
|
219 |
+
.tril(self.block_length)
|
220 |
+
)
|
221 |
+
scores = scores.masked_fill(block_mask == 0, -1e4)
|
222 |
+
p_attn = F.softmax(scores, dim=-1) # [b, n_h, t_t, t_s]
|
223 |
+
p_attn = self.drop(p_attn)
|
224 |
+
output = torch.matmul(p_attn, value)
|
225 |
+
if self.window_size is not None:
|
226 |
+
relative_weights = self._absolute_position_to_relative_position(p_attn)
|
227 |
+
value_relative_embeddings = self._get_relative_embeddings(
|
228 |
+
self.emb_rel_v, t_s
|
229 |
+
)
|
230 |
+
output = output + self._matmul_with_relative_values(
|
231 |
+
relative_weights, value_relative_embeddings
|
232 |
+
)
|
233 |
+
output = (
|
234 |
+
output.transpose(2, 3).contiguous().view(b, d, t_t)
|
235 |
+
) # [b, n_h, t_t, d_k] -> [b, d, t_t]
|
236 |
+
return output, p_attn
|
237 |
+
|
238 |
+
def _matmul_with_relative_values(self, x, y):
|
239 |
+
"""
|
240 |
+
x: [b, h, l, m]
|
241 |
+
y: [h or 1, m, d]
|
242 |
+
ret: [b, h, l, d]
|
243 |
+
"""
|
244 |
+
ret = torch.matmul(x, y.unsqueeze(0))
|
245 |
+
return ret
|
246 |
+
|
247 |
+
def _matmul_with_relative_keys(self, x, y):
|
248 |
+
"""
|
249 |
+
x: [b, h, l, d]
|
250 |
+
y: [h or 1, m, d]
|
251 |
+
ret: [b, h, l, m]
|
252 |
+
"""
|
253 |
+
ret = torch.matmul(x, y.unsqueeze(0).transpose(-2, -1))
|
254 |
+
return ret
|
255 |
+
|
256 |
+
def _get_relative_embeddings(self, relative_embeddings, length):
|
257 |
+
max_relative_position = 2 * self.window_size + 1
|
258 |
+
# Pad first before slice to avoid using cond ops.
|
259 |
+
pad_length = max(length - (self.window_size + 1), 0)
|
260 |
+
slice_start_position = max((self.window_size + 1) - length, 0)
|
261 |
+
slice_end_position = slice_start_position + 2 * length - 1
|
262 |
+
if pad_length > 0:
|
263 |
+
padded_relative_embeddings = F.pad(
|
264 |
+
relative_embeddings,
|
265 |
+
commons.convert_pad_shape([[0, 0], [pad_length, pad_length], [0, 0]]),
|
266 |
+
)
|
267 |
+
else:
|
268 |
+
padded_relative_embeddings = relative_embeddings
|
269 |
+
used_relative_embeddings = padded_relative_embeddings[
|
270 |
+
:, slice_start_position:slice_end_position
|
271 |
+
]
|
272 |
+
return used_relative_embeddings
|
273 |
+
|
274 |
+
def _relative_position_to_absolute_position(self, x):
|
275 |
+
"""
|
276 |
+
x: [b, h, l, 2*l-1]
|
277 |
+
ret: [b, h, l, l]
|
278 |
+
"""
|
279 |
+
batch, heads, length, _ = x.size()
|
280 |
+
# Concat columns of pad to shift from relative to absolute indexing.
|
281 |
+
x = F.pad(x, commons.convert_pad_shape([[0, 0], [0, 0], [0, 0], [0, 1]]))
|
282 |
+
|
283 |
+
# Concat extra elements so to add up to shape (len+1, 2*len-1).
|
284 |
+
x_flat = x.view([batch, heads, length * 2 * length])
|
285 |
+
x_flat = F.pad(
|
286 |
+
x_flat, commons.convert_pad_shape([[0, 0], [0, 0], [0, length - 1]])
|
287 |
+
)
|
288 |
+
|
289 |
+
# Reshape and slice out the padded elements.
|
290 |
+
x_final = x_flat.view([batch, heads, length + 1, 2 * length - 1])[
|
291 |
+
:, :, :length, length - 1 :
|
292 |
+
]
|
293 |
+
return x_final
|
294 |
+
|
295 |
+
def _absolute_position_to_relative_position(self, x):
|
296 |
+
"""
|
297 |
+
x: [b, h, l, l]
|
298 |
+
ret: [b, h, l, 2*l-1]
|
299 |
+
"""
|
300 |
+
batch, heads, length, _ = x.size()
|
301 |
+
# padd along column
|
302 |
+
x = F.pad(
|
303 |
+
x, commons.convert_pad_shape([[0, 0], [0, 0], [0, 0], [0, length - 1]])
|
304 |
+
)
|
305 |
+
x_flat = x.view([batch, heads, length**2 + length * (length - 1)])
|
306 |
+
# add 0's in the beginning that will skew the elements after reshape
|
307 |
+
x_flat = F.pad(x_flat, commons.convert_pad_shape([[0, 0], [0, 0], [length, 0]]))
|
308 |
+
x_final = x_flat.view([batch, heads, length, 2 * length])[:, :, :, 1:]
|
309 |
+
return x_final
|
310 |
+
|
311 |
+
def _attention_bias_proximal(self, length):
|
312 |
+
"""Bias for self-attention to encourage attention to close positions.
|
313 |
+
Args:
|
314 |
+
length: an integer scalar.
|
315 |
+
Returns:
|
316 |
+
a Tensor with shape [1, 1, length, length]
|
317 |
+
"""
|
318 |
+
r = torch.arange(length, dtype=torch.float32)
|
319 |
+
diff = torch.unsqueeze(r, 0) - torch.unsqueeze(r, 1)
|
320 |
+
return torch.unsqueeze(torch.unsqueeze(-torch.log1p(torch.abs(diff)), 0), 0)
|
321 |
+
|
322 |
+
|
323 |
+
class FFN(nn.Module):
|
324 |
+
def __init__(
|
325 |
+
self,
|
326 |
+
in_channels,
|
327 |
+
out_channels,
|
328 |
+
filter_channels,
|
329 |
+
kernel_size,
|
330 |
+
p_dropout=0.0,
|
331 |
+
activation=None,
|
332 |
+
causal=False,
|
333 |
+
):
|
334 |
+
super().__init__()
|
335 |
+
self.in_channels = in_channels
|
336 |
+
self.out_channels = out_channels
|
337 |
+
self.filter_channels = filter_channels
|
338 |
+
self.kernel_size = kernel_size
|
339 |
+
self.p_dropout = p_dropout
|
340 |
+
self.activation = activation
|
341 |
+
self.causal = causal
|
342 |
+
|
343 |
+
if causal:
|
344 |
+
self.padding = self._causal_padding
|
345 |
+
else:
|
346 |
+
self.padding = self._same_padding
|
347 |
+
|
348 |
+
self.conv_1 = nn.Conv1d(in_channels, filter_channels, kernel_size)
|
349 |
+
self.conv_2 = nn.Conv1d(filter_channels, out_channels, kernel_size)
|
350 |
+
self.drop = nn.Dropout(p_dropout)
|
351 |
+
|
352 |
+
def forward(self, x, x_mask):
|
353 |
+
x = self.conv_1(self.padding(x * x_mask))
|
354 |
+
if self.activation == "gelu":
|
355 |
+
x = x * torch.sigmoid(1.702 * x)
|
356 |
+
else:
|
357 |
+
x = torch.relu(x)
|
358 |
+
x = self.drop(x)
|
359 |
+
x = self.conv_2(self.padding(x * x_mask))
|
360 |
+
return x * x_mask
|
361 |
+
|
362 |
+
def _causal_padding(self, x):
|
363 |
+
if self.kernel_size == 1:
|
364 |
+
return x
|
365 |
+
pad_l = self.kernel_size - 1
|
366 |
+
pad_r = 0
|
367 |
+
padding = [[0, 0], [0, 0], [pad_l, pad_r]]
|
368 |
+
x = F.pad(x, commons.convert_pad_shape(padding))
|
369 |
+
return x
|
370 |
+
|
371 |
+
def _same_padding(self, x):
|
372 |
+
if self.kernel_size == 1:
|
373 |
+
return x
|
374 |
+
pad_l = (self.kernel_size - 1) // 2
|
375 |
+
pad_r = self.kernel_size // 2
|
376 |
+
padding = [[0, 0], [0, 0], [pad_l, pad_r]]
|
377 |
+
x = F.pad(x, commons.convert_pad_shape(padding))
|
378 |
+
return x
|
bert_gen.py
ADDED
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import argparse
|
2 |
+
from multiprocessing import Pool, cpu_count
|
3 |
+
|
4 |
+
import torch
|
5 |
+
import torch.multiprocessing as mp
|
6 |
+
from tqdm import tqdm
|
7 |
+
|
8 |
+
import commons
|
9 |
+
import utils
|
10 |
+
from config import config
|
11 |
+
from text import cleaned_text_to_sequence, get_bert
|
12 |
+
|
13 |
+
|
14 |
+
def process_line(line):
|
15 |
+
device = config.bert_gen_config.device
|
16 |
+
if config.bert_gen_config.use_multi_device:
|
17 |
+
rank = mp.current_process()._identity
|
18 |
+
rank = rank[0] if len(rank) > 0 else 0
|
19 |
+
if torch.cuda.is_available():
|
20 |
+
gpu_id = rank % torch.cuda.device_count()
|
21 |
+
device = torch.device(f"cuda:{gpu_id}")
|
22 |
+
else:
|
23 |
+
device = torch.device("cpu")
|
24 |
+
wav_path, _, language_str, text, phones, tone, word2ph = line.strip().split("|")
|
25 |
+
phone = phones.split(" ")
|
26 |
+
tone = [int(i) for i in tone.split(" ")]
|
27 |
+
word2ph = [int(i) for i in word2ph.split(" ")]
|
28 |
+
word2ph = [i for i in word2ph]
|
29 |
+
phone, tone, language = cleaned_text_to_sequence(phone, tone, language_str)
|
30 |
+
|
31 |
+
phone = commons.intersperse(phone, 0)
|
32 |
+
tone = commons.intersperse(tone, 0)
|
33 |
+
language = commons.intersperse(language, 0)
|
34 |
+
for i in range(len(word2ph)):
|
35 |
+
word2ph[i] = word2ph[i] * 2
|
36 |
+
word2ph[0] += 1
|
37 |
+
|
38 |
+
bert_path = wav_path.replace(".WAV", ".wav").replace(".wav", ".bert.pt")
|
39 |
+
|
40 |
+
try:
|
41 |
+
bert = torch.load(bert_path)
|
42 |
+
assert bert.shape[-1] == len(phone)
|
43 |
+
except Exception:
|
44 |
+
bert = get_bert(text, word2ph, language_str, device)
|
45 |
+
assert bert.shape[-1] == len(phone)
|
46 |
+
torch.save(bert, bert_path)
|
47 |
+
|
48 |
+
|
49 |
+
preprocess_text_config = config.preprocess_text_config
|
50 |
+
|
51 |
+
if __name__ == "__main__":
|
52 |
+
parser = argparse.ArgumentParser()
|
53 |
+
parser.add_argument(
|
54 |
+
"-c", "--config", type=str, default=config.bert_gen_config.config_path
|
55 |
+
)
|
56 |
+
parser.add_argument(
|
57 |
+
"--num_processes", type=int, default=config.bert_gen_config.num_processes
|
58 |
+
)
|
59 |
+
args, _ = parser.parse_known_args()
|
60 |
+
config_path = args.config
|
61 |
+
hps = utils.get_hparams_from_file(config_path)
|
62 |
+
lines = []
|
63 |
+
with open(hps.data.training_files, encoding="utf-8") as f:
|
64 |
+
lines.extend(f.readlines())
|
65 |
+
|
66 |
+
with open(hps.data.validation_files, encoding="utf-8") as f:
|
67 |
+
lines.extend(f.readlines())
|
68 |
+
if len(lines) != 0:
|
69 |
+
num_processes = min(args.num_processes, cpu_count())
|
70 |
+
with Pool(processes=num_processes) as pool:
|
71 |
+
for _ in tqdm(pool.imap_unordered(process_line, lines), total=len(lines)):
|
72 |
+
pass
|
73 |
+
|
74 |
+
print(f"bert生成完毕!, 共有{len(lines)}个bert.pt生成!")
|
commons.py
ADDED
@@ -0,0 +1,166 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import math
|
2 |
+
import torch
|
3 |
+
from torch.nn import functional as F
|
4 |
+
|
5 |
+
|
6 |
+
def init_weights(m, mean=0.0, std=0.01):
|
7 |
+
classname = m.__class__.__name__
|
8 |
+
if classname.find("Conv") != -1:
|
9 |
+
m.weight.data.normal_(mean, std)
|
10 |
+
|
11 |
+
|
12 |
+
def get_padding(kernel_size, dilation=1):
|
13 |
+
return int((kernel_size * dilation - dilation) / 2)
|
14 |
+
|
15 |
+
|
16 |
+
def convert_pad_shape(pad_shape):
|
17 |
+
layer = pad_shape[::-1]
|
18 |
+
pad_shape = [item for sublist in layer for item in sublist]
|
19 |
+
return pad_shape
|
20 |
+
|
21 |
+
|
22 |
+
def intersperse(lst, item):
|
23 |
+
result = [item] * (len(lst) * 2 + 1)
|
24 |
+
result[1::2] = lst
|
25 |
+
return result
|
26 |
+
|
27 |
+
|
28 |
+
def kl_divergence(m_p, logs_p, m_q, logs_q):
|
29 |
+
"""KL(P||Q)"""
|
30 |
+
kl = (logs_q - logs_p) - 0.5
|
31 |
+
kl += (
|
32 |
+
0.5 * (torch.exp(2.0 * logs_p) + ((m_p - m_q) ** 2)) * torch.exp(-2.0 * logs_q)
|
33 |
+
)
|
34 |
+
return kl
|
35 |
+
|
36 |
+
|
37 |
+
def rand_gumbel(shape):
|
38 |
+
"""Sample from the Gumbel distribution, protect from overflows."""
|
39 |
+
uniform_samples = torch.rand(shape) * 0.99998 + 0.00001
|
40 |
+
return -torch.log(-torch.log(uniform_samples))
|
41 |
+
|
42 |
+
|
43 |
+
def rand_gumbel_like(x):
|
44 |
+
g = rand_gumbel(x.size()).to(dtype=x.dtype, device=x.device)
|
45 |
+
return g
|
46 |
+
|
47 |
+
|
48 |
+
def slice_segments(x, ids_str, segment_size=4):
|
49 |
+
ret = torch.zeros_like(x[:, :, :segment_size])
|
50 |
+
for i in range(x.size(0)):
|
51 |
+
idx_str = ids_str[i]
|
52 |
+
idx_end = idx_str + segment_size
|
53 |
+
if idx_str < 0:
|
54 |
+
i1 = x.size(2) + idx_str
|
55 |
+
r1 = x[i, :, i1:]
|
56 |
+
r2 = x[i, :, :idx_end]
|
57 |
+
ret[i] = torch.cat([r1, r2], dim=1)
|
58 |
+
else:
|
59 |
+
ret[i] = x[i, :, idx_str:idx_end]
|
60 |
+
return ret
|
61 |
+
|
62 |
+
|
63 |
+
def rand_slice_segments(x, x_lengths=None, segment_size=4):
|
64 |
+
b, d, t = x.size()
|
65 |
+
if x_lengths is None:
|
66 |
+
x_lengths = t
|
67 |
+
ids_str_max = x_lengths - segment_size + 1
|
68 |
+
ids_str = (torch.rand([b]).to(device=x.device) * ids_str_max).to(dtype=torch.long)
|
69 |
+
ret = slice_segments(x, ids_str, segment_size)
|
70 |
+
return ret, ids_str
|
71 |
+
|
72 |
+
|
73 |
+
def get_timing_signal_1d(length, channels, min_timescale=1.0, max_timescale=1.0e4):
|
74 |
+
position = torch.arange(length, dtype=torch.float)
|
75 |
+
num_timescales = channels // 2
|
76 |
+
log_timescale_increment = math.log(float(max_timescale) / float(min_timescale)) / (
|
77 |
+
num_timescales - 1
|
78 |
+
)
|
79 |
+
inv_timescales = min_timescale * torch.exp(
|
80 |
+
torch.arange(num_timescales, dtype=torch.float) * -log_timescale_increment
|
81 |
+
)
|
82 |
+
scaled_time = position.unsqueeze(0) * inv_timescales.unsqueeze(1)
|
83 |
+
signal = torch.cat([torch.sin(scaled_time), torch.cos(scaled_time)], 0)
|
84 |
+
signal = F.pad(signal, [0, 0, 0, channels % 2])
|
85 |
+
signal = signal.view(1, channels, length)
|
86 |
+
return signal
|
87 |
+
|
88 |
+
|
89 |
+
def add_timing_signal_1d(x, min_timescale=1.0, max_timescale=1.0e4):
|
90 |
+
b, channels, length = x.size()
|
91 |
+
signal = get_timing_signal_1d(length, channels, min_timescale, max_timescale)
|
92 |
+
return x + signal.to(dtype=x.dtype, device=x.device)
|
93 |
+
|
94 |
+
|
95 |
+
def cat_timing_signal_1d(x, min_timescale=1.0, max_timescale=1.0e4, axis=1):
|
96 |
+
b, channels, length = x.size()
|
97 |
+
signal = get_timing_signal_1d(length, channels, min_timescale, max_timescale)
|
98 |
+
return torch.cat([x, signal.to(dtype=x.dtype, device=x.device)], axis)
|
99 |
+
|
100 |
+
|
101 |
+
def subsequent_mask(length):
|
102 |
+
mask = torch.tril(torch.ones(length, length)).unsqueeze(0).unsqueeze(0)
|
103 |
+
return mask
|
104 |
+
|
105 |
+
|
106 |
+
@torch.jit.script
|
107 |
+
def fused_add_tanh_sigmoid_multiply(input_a, input_b, n_channels):
|
108 |
+
n_channels_int = n_channels[0]
|
109 |
+
in_act = input_a + input_b
|
110 |
+
t_act = torch.tanh(in_act[:, :n_channels_int, :])
|
111 |
+
s_act = torch.sigmoid(in_act[:, n_channels_int:, :])
|
112 |
+
acts = t_act * s_act
|
113 |
+
return acts
|
114 |
+
|
115 |
+
|
116 |
+
def convert_pad_shape(pad_shape):
|
117 |
+
layer = pad_shape[::-1]
|
118 |
+
pad_shape = [item for sublist in layer for item in sublist]
|
119 |
+
return pad_shape
|
120 |
+
|
121 |
+
|
122 |
+
def shift_1d(x):
|
123 |
+
x = F.pad(x, convert_pad_shape([[0, 0], [0, 0], [1, 0]]))[:, :, :-1]
|
124 |
+
return x
|
125 |
+
|
126 |
+
|
127 |
+
def sequence_mask(length, max_length=None):
|
128 |
+
if max_length is None:
|
129 |
+
max_length = length.max()
|
130 |
+
x = torch.arange(max_length, dtype=length.dtype, device=length.device)
|
131 |
+
return x.unsqueeze(0) < length.unsqueeze(1)
|
132 |
+
|
133 |
+
|
134 |
+
def generate_path(duration, mask):
|
135 |
+
"""
|
136 |
+
duration: [b, 1, t_x]
|
137 |
+
mask: [b, 1, t_y, t_x]
|
138 |
+
"""
|
139 |
+
|
140 |
+
b, _, t_y, t_x = mask.shape
|
141 |
+
cum_duration = torch.cumsum(duration, -1)
|
142 |
+
|
143 |
+
cum_duration_flat = cum_duration.view(b * t_x)
|
144 |
+
path = sequence_mask(cum_duration_flat, t_y).to(mask.dtype)
|
145 |
+
path = path.view(b, t_x, t_y)
|
146 |
+
path = path - F.pad(path, convert_pad_shape([[0, 0], [1, 0], [0, 0]]))[:, :-1]
|
147 |
+
path = path.unsqueeze(1).transpose(2, 3) * mask
|
148 |
+
return path
|
149 |
+
|
150 |
+
|
151 |
+
def clip_grad_value_(parameters, clip_value, norm_type=2):
|
152 |
+
if isinstance(parameters, torch.Tensor):
|
153 |
+
parameters = [parameters]
|
154 |
+
parameters = list(filter(lambda p: p.grad is not None, parameters))
|
155 |
+
norm_type = float(norm_type)
|
156 |
+
if clip_value is not None:
|
157 |
+
clip_value = float(clip_value)
|
158 |
+
|
159 |
+
total_norm = 0
|
160 |
+
for p in parameters:
|
161 |
+
param_norm = p.grad.data.norm(norm_type)
|
162 |
+
total_norm += param_norm.item() ** norm_type
|
163 |
+
if clip_value is not None:
|
164 |
+
p.grad.data.clamp_(min=-clip_value, max=clip_value)
|
165 |
+
total_norm = total_norm ** (1.0 / norm_type)
|
166 |
+
return total_norm
|
compress_model.py
ADDED
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from collections import OrderedDict
|
2 |
+
from text.symbols import symbols
|
3 |
+
import torch
|
4 |
+
from tools.log import logger
|
5 |
+
import utils
|
6 |
+
from models import SynthesizerTrn
|
7 |
+
import os
|
8 |
+
|
9 |
+
|
10 |
+
def copyStateDict(state_dict):
|
11 |
+
if list(state_dict.keys())[0].startswith("module"):
|
12 |
+
start_idx = 1
|
13 |
+
else:
|
14 |
+
start_idx = 0
|
15 |
+
new_state_dict = OrderedDict()
|
16 |
+
for k, v in state_dict.items():
|
17 |
+
name = ",".join(k.split(".")[start_idx:])
|
18 |
+
new_state_dict[name] = v
|
19 |
+
return new_state_dict
|
20 |
+
|
21 |
+
|
22 |
+
def removeOptimizer(config: str, input_model: str, ishalf: bool, output_model: str):
|
23 |
+
hps = utils.get_hparams_from_file(config)
|
24 |
+
|
25 |
+
net_g = SynthesizerTrn(
|
26 |
+
len(symbols),
|
27 |
+
hps.data.filter_length // 2 + 1,
|
28 |
+
hps.train.segment_size // hps.data.hop_length,
|
29 |
+
n_speakers=hps.data.n_speakers,
|
30 |
+
**hps.model,
|
31 |
+
)
|
32 |
+
|
33 |
+
optim_g = torch.optim.AdamW(
|
34 |
+
net_g.parameters(),
|
35 |
+
hps.train.learning_rate,
|
36 |
+
betas=hps.train.betas,
|
37 |
+
eps=hps.train.eps,
|
38 |
+
)
|
39 |
+
|
40 |
+
state_dict_g = torch.load(input_model, map_location="cpu")
|
41 |
+
new_dict_g = copyStateDict(state_dict_g)
|
42 |
+
keys = []
|
43 |
+
for k, v in new_dict_g["model"].items():
|
44 |
+
if "enc_q" in k:
|
45 |
+
continue # noqa: E701
|
46 |
+
keys.append(k)
|
47 |
+
|
48 |
+
new_dict_g = (
|
49 |
+
{k: new_dict_g["model"][k].half() for k in keys}
|
50 |
+
if ishalf
|
51 |
+
else {k: new_dict_g["model"][k] for k in keys}
|
52 |
+
)
|
53 |
+
|
54 |
+
torch.save(
|
55 |
+
{
|
56 |
+
"model": new_dict_g,
|
57 |
+
"iteration": 0,
|
58 |
+
"optimizer": optim_g.state_dict(),
|
59 |
+
"learning_rate": 0.0001,
|
60 |
+
},
|
61 |
+
output_model,
|
62 |
+
)
|
63 |
+
|
64 |
+
|
65 |
+
if __name__ == "__main__":
|
66 |
+
import argparse
|
67 |
+
|
68 |
+
parser = argparse.ArgumentParser()
|
69 |
+
parser.add_argument("-c", "--config", type=str, default="configs/config.json")
|
70 |
+
parser.add_argument("-i", "--input", type=str)
|
71 |
+
parser.add_argument("-o", "--output", type=str, default=None)
|
72 |
+
parser.add_argument(
|
73 |
+
"-hf", "--half", action="store_true", default=False, help="Save as FP16"
|
74 |
+
)
|
75 |
+
|
76 |
+
args = parser.parse_args()
|
77 |
+
|
78 |
+
output = args.output
|
79 |
+
|
80 |
+
if output is None:
|
81 |
+
import os.path
|
82 |
+
|
83 |
+
filename, ext = os.path.splitext(args.input)
|
84 |
+
half = "_half" if args.half else ""
|
85 |
+
output = filename + "_release" + half + ext
|
86 |
+
|
87 |
+
removeOptimizer(args.config, args.input, args.half, output)
|
88 |
+
logger.info(f"压缩模型成功, 输出模型: {os.path.abspath(output)}")
|
config.py
ADDED
@@ -0,0 +1,244 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
@Desc: 全局配置文件读取
|
3 |
+
"""
|
4 |
+
import argparse
|
5 |
+
import yaml
|
6 |
+
from typing import Dict, List
|
7 |
+
import os
|
8 |
+
import shutil
|
9 |
+
import sys
|
10 |
+
|
11 |
+
|
12 |
+
class Resample_config:
|
13 |
+
"""重采样配置"""
|
14 |
+
|
15 |
+
def __init__(self, in_dir: str, out_dir: str, sampling_rate: int = 44100):
|
16 |
+
self.sampling_rate: int = sampling_rate # 目标采样率
|
17 |
+
self.in_dir: str = in_dir # 待处理音频目录路径
|
18 |
+
self.out_dir: str = out_dir # 重采样输出路径
|
19 |
+
|
20 |
+
@classmethod
|
21 |
+
def from_dict(cls, dataset_path: str, data: Dict[str, any]):
|
22 |
+
"""从字典中生成实例"""
|
23 |
+
|
24 |
+
# 不检查路径是否有效,此逻辑在resample.py中处理
|
25 |
+
data["in_dir"] = os.path.join(dataset_path, data["in_dir"])
|
26 |
+
data["out_dir"] = os.path.join(dataset_path, data["out_dir"])
|
27 |
+
|
28 |
+
return cls(**data)
|
29 |
+
|
30 |
+
|
31 |
+
class Preprocess_text_config:
|
32 |
+
"""数据预处理配置"""
|
33 |
+
|
34 |
+
def __init__(
|
35 |
+
self,
|
36 |
+
transcription_path: str,
|
37 |
+
cleaned_path: str,
|
38 |
+
train_path: str,
|
39 |
+
val_path: str,
|
40 |
+
config_path: str,
|
41 |
+
val_per_spk: int = 5,
|
42 |
+
max_val_total: int = 10000,
|
43 |
+
clean: bool = True,
|
44 |
+
):
|
45 |
+
self.transcription_path: str = transcription_path # 原始文本文件路径,文本格式应为{wav_path}|{speaker_name}|{language}|{text}。
|
46 |
+
self.cleaned_path: str = cleaned_path # 数据清洗后文本路径,可以不填。不填则将在原始文本目录生成
|
47 |
+
self.train_path: str = train_path # 训练集路径,可以不填。不填则将在原始文本目录生成
|
48 |
+
self.val_path: str = val_path # 验证集路径,可以不填。不填则将在原始文本目录生成
|
49 |
+
self.config_path: str = config_path # 配置文件路径
|
50 |
+
self.val_per_spk: int = val_per_spk # 每个speaker的验证集条数
|
51 |
+
self.max_val_total: int = max_val_total # 验证集最大条数,多于的会被截断并放到训练集中
|
52 |
+
self.clean: bool = clean # 是否进行数据清洗
|
53 |
+
|
54 |
+
@classmethod
|
55 |
+
def from_dict(cls, dataset_path: str, data: Dict[str, any]):
|
56 |
+
"""从字典中生成实例"""
|
57 |
+
|
58 |
+
data["transcription_path"] = os.path.join(
|
59 |
+
dataset_path, data["transcription_path"]
|
60 |
+
)
|
61 |
+
if data["cleaned_path"] == "" or data["cleaned_path"] is None:
|
62 |
+
data["cleaned_path"] = None
|
63 |
+
else:
|
64 |
+
data["cleaned_path"] = os.path.join(dataset_path, data["cleaned_path"])
|
65 |
+
data["train_path"] = os.path.join(dataset_path, data["train_path"])
|
66 |
+
data["val_path"] = os.path.join(dataset_path, data["val_path"])
|
67 |
+
data["config_path"] = os.path.join(dataset_path, data["config_path"])
|
68 |
+
|
69 |
+
return cls(**data)
|
70 |
+
|
71 |
+
|
72 |
+
class Bert_gen_config:
|
73 |
+
"""bert_gen 配置"""
|
74 |
+
|
75 |
+
def __init__(
|
76 |
+
self,
|
77 |
+
config_path: str,
|
78 |
+
num_processes: int = 2,
|
79 |
+
device: str = "cuda",
|
80 |
+
use_multi_device: bool = False,
|
81 |
+
):
|
82 |
+
self.config_path = config_path
|
83 |
+
self.num_processes = num_processes
|
84 |
+
self.device = device
|
85 |
+
self.use_multi_device = use_multi_device
|
86 |
+
|
87 |
+
@classmethod
|
88 |
+
def from_dict(cls, dataset_path: str, data: Dict[str, any]):
|
89 |
+
data["config_path"] = os.path.join(dataset_path, data["config_path"])
|
90 |
+
|
91 |
+
return cls(**data)
|
92 |
+
|
93 |
+
|
94 |
+
class Emo_gen_config:
|
95 |
+
"""emo_gen 配置"""
|
96 |
+
|
97 |
+
def __init__(
|
98 |
+
self,
|
99 |
+
config_path: str,
|
100 |
+
num_processes: int = 2,
|
101 |
+
device: str = "cuda",
|
102 |
+
):
|
103 |
+
self.config_path = config_path
|
104 |
+
self.num_processes = num_processes
|
105 |
+
self.device = device
|
106 |
+
|
107 |
+
@classmethod
|
108 |
+
def from_dict(cls, dataset_path: str, data: Dict[str, any]):
|
109 |
+
data["config_path"] = os.path.join(dataset_path, data["config_path"])
|
110 |
+
|
111 |
+
return cls(**data)
|
112 |
+
|
113 |
+
|
114 |
+
class Train_ms_config:
|
115 |
+
"""训练配置"""
|
116 |
+
|
117 |
+
def __init__(
|
118 |
+
self,
|
119 |
+
config_path: str,
|
120 |
+
env: Dict[str, any],
|
121 |
+
base: Dict[str, any],
|
122 |
+
model: str,
|
123 |
+
num_workers: int,
|
124 |
+
spec_cache: bool,
|
125 |
+
keep_ckpts: int,
|
126 |
+
):
|
127 |
+
self.env = env # 需要加载的环境变量
|
128 |
+
self.base = base # 底模配置
|
129 |
+
self.model = model # 训练模型存储目录,该路径为相对于dataset_path的路径,而非项目根目录
|
130 |
+
self.config_path = config_path # 配置文件路径
|
131 |
+
self.num_workers = num_workers # worker数量
|
132 |
+
self.spec_cache = spec_cache # 是否启用spec缓存
|
133 |
+
self.keep_ckpts = keep_ckpts # ckpt数量
|
134 |
+
|
135 |
+
@classmethod
|
136 |
+
def from_dict(cls, dataset_path: str, data: Dict[str, any]):
|
137 |
+
# data["model"] = os.path.join(dataset_path, data["model"])
|
138 |
+
data["config_path"] = os.path.join(dataset_path, data["config_path"])
|
139 |
+
|
140 |
+
return cls(**data)
|
141 |
+
|
142 |
+
|
143 |
+
class Webui_config:
|
144 |
+
"""webui 配置"""
|
145 |
+
|
146 |
+
def __init__(
|
147 |
+
self,
|
148 |
+
device: str,
|
149 |
+
model: str,
|
150 |
+
config_path: str,
|
151 |
+
language_identification_library: str,
|
152 |
+
port: int = 7860,
|
153 |
+
share: bool = False,
|
154 |
+
debug: bool = False,
|
155 |
+
):
|
156 |
+
self.device: str = device
|
157 |
+
self.model: str = model # 端口号
|
158 |
+
self.config_path: str = config_path # 是否公开部署,对外网开放
|
159 |
+
self.port: int = port # 是否开启debug模式
|
160 |
+
self.share: bool = share # 模型路径
|
161 |
+
self.debug: bool = debug # 配置文件路径
|
162 |
+
self.language_identification_library: str = (
|
163 |
+
language_identification_library # 语种识别库
|
164 |
+
)
|
165 |
+
|
166 |
+
@classmethod
|
167 |
+
def from_dict(cls, dataset_path: str, data: Dict[str, any]):
|
168 |
+
data["config_path"] = os.path.join(dataset_path, data["config_path"])
|
169 |
+
data["model"] = os.path.join(dataset_path, data["model"])
|
170 |
+
return cls(**data)
|
171 |
+
|
172 |
+
|
173 |
+
class Server_config:
|
174 |
+
def __init__(
|
175 |
+
self, models: List[Dict[str, any]], port: int = 5000, device: str = "cuda"
|
176 |
+
):
|
177 |
+
self.models: List[Dict[str, any]] = models # 需要加载的所有模型的配置
|
178 |
+
self.port: int = port # 端口号
|
179 |
+
self.device: str = device # 模型默认使用设备
|
180 |
+
|
181 |
+
@classmethod
|
182 |
+
def from_dict(cls, data: Dict[str, any]):
|
183 |
+
return cls(**data)
|
184 |
+
|
185 |
+
|
186 |
+
class Translate_config:
|
187 |
+
"""翻译api配置"""
|
188 |
+
|
189 |
+
def __init__(self, app_key: str, secret_key: str):
|
190 |
+
self.app_key = app_key
|
191 |
+
self.secret_key = secret_key
|
192 |
+
|
193 |
+
@classmethod
|
194 |
+
def from_dict(cls, data: Dict[str, any]):
|
195 |
+
return cls(**data)
|
196 |
+
|
197 |
+
|
198 |
+
class Config:
|
199 |
+
def __init__(self, config_path: str):
|
200 |
+
if not os.path.isfile(config_path) and os.path.isfile("default_config.yml"):
|
201 |
+
shutil.copy(src="default_config.yml", dst=config_path)
|
202 |
+
print(
|
203 |
+
f"已根据默认配置文件default_config.yml生成配置文件{config_path}。请按该配置文件的说明进行配置后重新运行。"
|
204 |
+
)
|
205 |
+
print("如无特殊需求,请勿修改default_config.yml或备份该文件。")
|
206 |
+
sys.exit(0)
|
207 |
+
with open(file=config_path, mode="r", encoding="utf-8") as file:
|
208 |
+
yaml_config: Dict[str, any] = yaml.safe_load(file.read())
|
209 |
+
dataset_path: str = yaml_config["dataset_path"]
|
210 |
+
openi_token: str = yaml_config["openi_token"]
|
211 |
+
self.dataset_path: str = dataset_path
|
212 |
+
self.mirror: str = yaml_config["mirror"]
|
213 |
+
self.openi_token: str = openi_token
|
214 |
+
self.resample_config: Resample_config = Resample_config.from_dict(
|
215 |
+
dataset_path, yaml_config["resample"]
|
216 |
+
)
|
217 |
+
self.preprocess_text_config: Preprocess_text_config = (
|
218 |
+
Preprocess_text_config.from_dict(
|
219 |
+
dataset_path, yaml_config["preprocess_text"]
|
220 |
+
)
|
221 |
+
)
|
222 |
+
self.bert_gen_config: Bert_gen_config = Bert_gen_config.from_dict(
|
223 |
+
dataset_path, yaml_config["bert_gen"]
|
224 |
+
)
|
225 |
+
self.train_ms_config: Train_ms_config = Train_ms_config.from_dict(
|
226 |
+
dataset_path, yaml_config["train_ms"]
|
227 |
+
)
|
228 |
+
self.webui_config: Webui_config = Webui_config.from_dict(
|
229 |
+
dataset_path, yaml_config["webui"]
|
230 |
+
)
|
231 |
+
self.server_config: Server_config = Server_config.from_dict(
|
232 |
+
yaml_config["server"]
|
233 |
+
)
|
234 |
+
self.translate_config: Translate_config = Translate_config.from_dict(
|
235 |
+
yaml_config["translate"]
|
236 |
+
)
|
237 |
+
|
238 |
+
|
239 |
+
parser = argparse.ArgumentParser()
|
240 |
+
# 为避免与以前的config.json起冲突,将其更名如下
|
241 |
+
parser.add_argument("-y", "--yml_config", type=str, default="config.yml")
|
242 |
+
args, _ = parser.parse_known_args()
|
243 |
+
config = Config(args.yml_config)
|
244 |
+
yml_config = args.yml_config
|