whisperspeech2 0.9.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ __version__ = "0.9.0"
@@ -0,0 +1,72 @@
1
+ __all__ = ['Vocoder']
2
+
3
+ from vocos import Vocos
4
+ from whisperspeech2 import inference
5
+ import torch
6
+
7
+ class Vocoder:
8
+ def __init__(self, repo_id="charactr/vocos-encodec-24khz", device=None, cache_dir=None):
9
+ if device is None: device = inference.get_compute_device()
10
+ if device == 'mps': device = 'cpu'
11
+ self.device = device
12
+ self.vocos = Vocos.from_pretrained(repo_id).to(device)
13
+
14
+ def is_notebook(self):
15
+ try:
16
+ return get_ipython().__class__.__name__ == "ZMQInteractiveShell"
17
+ except:
18
+ return False
19
+
20
+ @torch.no_grad()
21
+ def decode(self, atoks):
22
+ if len(atoks.shape) == 3:
23
+ b,q,t = atoks.shape
24
+ atoks = atoks.permute(1,0,2)
25
+ else:
26
+ q,t = atoks.shape
27
+ atoks = atoks.to(self.device)
28
+ features = self.vocos.codes_to_features(atoks)
29
+ bandwidth_id = torch.tensor({2: 0, 4: 1, 8: 2}[q]).to(self.device)
30
+ return self.vocos.decode(features, bandwidth_id=bandwidth_id)
31
+
32
+ def _save_audio(self, fname, audio_tensor, sample_rate=24000):
33
+ try:
34
+ import torchaudio
35
+ torchaudio.save(fname, audio_tensor, sample_rate, backend="soundfile")
36
+ return
37
+ except (ImportError, RuntimeError, TypeError):
38
+ pass
39
+
40
+ try:
41
+ import torchaudio
42
+ torchaudio.save(fname, audio_tensor, sample_rate)
43
+ return
44
+ except (ImportError, RuntimeError):
45
+ pass
46
+
47
+ try:
48
+ import soundfile as sf
49
+ audio_np = audio_tensor.numpy().T
50
+ sf.write(fname, audio_np, sample_rate)
51
+ return
52
+ except ImportError:
53
+ pass
54
+
55
+ raise ImportError(
56
+ "No audio backend available. Please install either torchaudio or soundfile:\n"
57
+ " pip install torchaudio\n"
58
+ "or\n"
59
+ " pip install soundfile"
60
+ )
61
+
62
+ def decode_to_file(self, fname, atoks):
63
+ audio = self.decode(atoks)
64
+ self._save_audio(fname, audio.cpu(), 24000)
65
+ if self.is_notebook():
66
+ from IPython.display import display, HTML, Audio
67
+ display(HTML(f'<a href="{fname}" target="_blank">Listen to {fname}</a>'))
68
+
69
+ def decode_to_notebook(self, atoks):
70
+ from IPython.display import display, HTML, Audio
71
+ audio = self.decode(atoks)
72
+ display(Audio(audio.cpu().numpy(), rate=24000))
@@ -0,0 +1,56 @@
1
+ __all__ = ['get_compute_device']
2
+
3
+ import torch
4
+ import torch.nn.functional as F
5
+ from huggingface_hub import hf_hub_download
6
+ from contextlib import nullcontext
7
+
8
+ def get_default_compute_device():
9
+ if torch.cuda.is_available() and (torch.version.cuda or torch.version.hip):
10
+ return 'cuda'
11
+ elif torch.backends.mps.is_available():
12
+ return 'mps'
13
+ else:
14
+ return 'cpu'
15
+
16
+ preferred_device = None
17
+
18
+ def get_compute_device():
19
+ global preferred_device
20
+ if preferred_device is None: preferred_device = get_default_compute_device()
21
+ return preferred_device
22
+
23
+ def load_model(ref=None, spec=None, device='cpu', cache_dir=None):
24
+ if spec is not None: return spec
25
+ if ":" in ref:
26
+ repo_id, filename = ref.split(":", 1)
27
+ local_filename = hf_hub_download(repo_id=repo_id, filename=filename, cache_dir=cache_dir)
28
+ else:
29
+ local_filename = ref
30
+ return torch.load(local_filename, map_location=device)
31
+
32
+ def inference_context():
33
+ if torch.cuda.is_available():
34
+ return torch.backends.cuda.sdp_kernel(enable_flash=False, enable_mem_efficient=False, enable_math=True)
35
+ else:
36
+ return nullcontext()
37
+
38
+ def multinomial_sample_one_no_sync(probs_sort):
39
+ q = torch.empty_like(probs_sort).exponential_(1)
40
+ return torch.argmax(probs_sort / q, dim=-1, keepdim=True).to(dtype=torch.int)
41
+
42
+ def logits_to_probs(logits, T=1.0, top_k=None):
43
+ logits = logits / max(T, 1e-5)
44
+
45
+ if top_k is not None:
46
+ v, _ = torch.topk(logits, min(top_k, logits.size(-1)))
47
+ pivot = v.select(-1, -1).unsqueeze(-1)
48
+ logits = torch.where(logits < pivot, -float("Inf"), logits)
49
+
50
+ probs = torch.nn.functional.softmax(logits, dim=-1)
51
+ return probs
52
+
53
+ def sample(logits, T=1.0, top_k=None):
54
+ probs = logits_to_probs(logits, T, top_k)
55
+ idx_next = multinomial_sample_one_no_sync(probs)
56
+ return idx_next
@@ -0,0 +1,131 @@
1
+ # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/B. Languages.ipynb.
2
+
3
+ # %% auto 0
4
+ __all__ = ['to_id']
5
+
6
+ # %% ../nbs/B. Languages.ipynb 3
7
+ LANGUAGES = {
8
+ "en": "english",
9
+ "zh": "chinese",
10
+ "de": "german",
11
+ "es": "spanish",
12
+ "ru": "russian",
13
+ "ko": "korean",
14
+ "fr": "french",
15
+ "ja": "japanese",
16
+ "pt": "portuguese",
17
+ "tr": "turkish",
18
+ "pl": "polish",
19
+ "ca": "catalan",
20
+ "nl": "dutch",
21
+ "ar": "arabic",
22
+ "sv": "swedish",
23
+ "it": "italian",
24
+ "id": "indonesian",
25
+ "hi": "hindi",
26
+ "fi": "finnish",
27
+ "vi": "vietnamese",
28
+ "he": "hebrew",
29
+ "uk": "ukrainian",
30
+ "el": "greek",
31
+ "ms": "malay",
32
+ "cs": "czech",
33
+ "ro": "romanian",
34
+ "da": "danish",
35
+ "hu": "hungarian",
36
+ "ta": "tamil",
37
+ "no": "norwegian",
38
+ "th": "thai",
39
+ "ur": "urdu",
40
+ "hr": "croatian",
41
+ "bg": "bulgarian",
42
+ "lt": "lithuanian",
43
+ "la": "latin",
44
+ "mi": "maori",
45
+ "ml": "malayalam",
46
+ "cy": "welsh",
47
+ "sk": "slovak",
48
+ "te": "telugu",
49
+ "fa": "persian",
50
+ "lv": "latvian",
51
+ "bn": "bengali",
52
+ "sr": "serbian",
53
+ "az": "azerbaijani",
54
+ "sl": "slovenian",
55
+ "kn": "kannada",
56
+ "et": "estonian",
57
+ "mk": "macedonian",
58
+ "br": "breton",
59
+ "eu": "basque",
60
+ "is": "icelandic",
61
+ "hy": "armenian",
62
+ "ne": "nepali",
63
+ "mn": "mongolian",
64
+ "bs": "bosnian",
65
+ "kk": "kazakh",
66
+ "sq": "albanian",
67
+ "sw": "swahili",
68
+ "gl": "galician",
69
+ "mr": "marathi",
70
+ "pa": "punjabi",
71
+ "si": "sinhala",
72
+ "km": "khmer",
73
+ "sn": "shona",
74
+ "yo": "yoruba",
75
+ "so": "somali",
76
+ "af": "afrikaans",
77
+ "oc": "occitan",
78
+ "ka": "georgian",
79
+ "be": "belarusian",
80
+ "tg": "tajik",
81
+ "sd": "sindhi",
82
+ "gu": "gujarati",
83
+ "am": "amharic",
84
+ "yi": "yiddish",
85
+ "lo": "lao",
86
+ "uz": "uzbek",
87
+ "fo": "faroese",
88
+ "ht": "haitian creole",
89
+ "ps": "pashto",
90
+ "tk": "turkmen",
91
+ "nn": "nynorsk",
92
+ "mt": "maltese",
93
+ "sa": "sanskrit",
94
+ "lb": "luxembourgish",
95
+ "my": "myanmar",
96
+ "bo": "tibetan",
97
+ "tl": "tagalog",
98
+ "mg": "malagasy",
99
+ "as": "assamese",
100
+ "tt": "tatar",
101
+ "haw": "hawaiian",
102
+ "ln": "lingala",
103
+ "ha": "hausa",
104
+ "ba": "bashkir",
105
+ "jw": "javanese",
106
+ "su": "sundanese",
107
+ }
108
+
109
+ # %% ../nbs/B. Languages.ipynb 4
110
+ # language code lookup by name, with a few language aliases
111
+ TO_LANGUAGE_CODE = {
112
+ **{language: code for code, language in LANGUAGES.items()},
113
+ "burmese": "my",
114
+ "valencian": "ca",
115
+ "flemish": "nl",
116
+ "haitian": "ht",
117
+ "letzeburgesch": "lb",
118
+ "pushto": "ps",
119
+ "panjabi": "pa",
120
+ "moldavian": "ro",
121
+ "moldovan": "ro",
122
+ "sinhalese": "si",
123
+ "castilian": "es",
124
+ }
125
+
126
+ # %% ../nbs/B. Languages.ipynb 5
127
+ languages = tuple(LANGUAGES.keys())
128
+
129
+ # %% ../nbs/B. Languages.ipynb 6
130
+ def to_id(lang):
131
+ return languages.index(TO_LANGUAGE_CODE.get(lang, lang))
@@ -0,0 +1,303 @@
1
+ __all__ = ['LayerNorm', 'LinearHead', 'QueryHead', 'init_transformer', 'sinusoids', 'MultiHeadAttention',
2
+ 'ResidualAttentionBlock', 'BaseDecoder', 'EmbeddingProjector', 'FlexEmbeddings']
3
+
4
+ import torch
5
+ import numpy as np
6
+ import math
7
+
8
+ from torch import Tensor, nn
9
+ import torch.nn.functional as F
10
+ from typing import Dict, Iterable, Optional
11
+
12
+ class LayerNorm(nn.LayerNorm):
13
+ def forward(self, x):
14
+ return super().forward(x.float()).type(x.dtype)
15
+
16
+ class LinearHead(nn.Linear):
17
+ pass
18
+
19
+ class QueryHead(nn.Linear):
20
+ pass
21
+
22
+ def init_transformer(m):
23
+ if isinstance(m, (nn.Linear, nn.Embedding)):
24
+ torch.nn.init.trunc_normal_(m.weight, std=.02)
25
+ if isinstance(m, nn.Linear) and m.bias is not None:
26
+ torch.nn.init.constant_(m.bias, 0)
27
+ elif isinstance(m, nn.LayerNorm):
28
+ torch.nn.init.constant_(m.bias, 0)
29
+ torch.nn.init.constant_(m.weight, 1.0)
30
+
31
+ def sinusoids(length, channels, max_timescale=10000):
32
+ assert channels % 2 == 0
33
+ log_timescale_increment = np.log(max_timescale) / (channels // 2 - 1)
34
+ inv_timescales = torch.exp(-log_timescale_increment * torch.arange(channels // 2))
35
+ scaled_time = torch.arange(length)[:, np.newaxis] * inv_timescales[np.newaxis, :]
36
+ return torch.cat([torch.sin(scaled_time), torch.cos(scaled_time)], dim=1)
37
+
38
+ class MultiHeadAttention(nn.Module):
39
+ def __init__(self, n_state: int, n_head: int, qk_scale: float = 1, rope: bool = False, cross=False):
40
+ super().__init__()
41
+ self.n_state = n_state
42
+ self.n_head = n_head
43
+ self.sqrt_qk_scale = math.sqrt(qk_scale)
44
+ self.query = QueryHead(n_state, n_state)
45
+ self.key = nn.Linear(n_state, n_state, bias=False)
46
+ self.value = nn.Linear(n_state, n_state)
47
+ self.out = nn.Linear(n_state, n_state)
48
+ self.cross = cross
49
+ self.query_subsampling = 1
50
+ self.key_subsampling = 1
51
+
52
+ self.cached_kvx = None
53
+ self.register_buffer('k_cache', None)
54
+ self.register_buffer('v_cache', None)
55
+
56
+ self.rotary = None
57
+ if rope:
58
+ self.rotary = Rotary(n_state // n_head)
59
+ self.qkv = None
60
+ self.kv = None
61
+
62
+ def setup_kv_cache(self, max_batch_size, max_seq_len, dtype=torch.float32):
63
+ cache_shape = (max_batch_size, self.n_head, max_seq_len, self.n_state//self.n_head)
64
+ self.k_cache = torch.zeros(cache_shape, dtype=dtype, device=self.key.weight.device)
65
+ self.v_cache = torch.zeros(cache_shape, dtype=dtype, device=self.value.weight.device)
66
+
67
+ def merge_linears(self, layers, mults):
68
+ bias = [x.bias for x in layers if x.bias is not None][0]
69
+ din, dout = layers[0].weight.shape
70
+ new = nn.Linear(din, len(layers) * dout).to(layers[0].weight.device)
71
+ with torch.no_grad():
72
+ new.weight[:] = torch.cat([x.weight * m for x,m in zip(layers, mults)])
73
+ new.bias[:] = torch.cat([torch.zeros_like(bias) if x.bias is None else x.bias * m for x, m in zip(layers, mults)])
74
+ return new
75
+
76
+ def convert_for_eval(self):
77
+ if self.qkv or self.kv: raise AttributeError("already converted")
78
+
79
+ self.odim = self.key.weight.shape[1]
80
+ if self.cross:
81
+ self.q = self.merge_linears([self.query], [self.sqrt_qk_scale])
82
+ self.kv = self.merge_linears([self.key, self.value],
83
+ [self.sqrt_qk_scale, 1])
84
+ else:
85
+ self.qkv = self.merge_linears([self.query, self.key, self.value],
86
+ [self.sqrt_qk_scale, self.sqrt_qk_scale, 1])
87
+
88
+ def split_heads(self, x, x_positions, rope=False, subsampling=1):
89
+ x = x.view(*x.shape[:2], self.n_head, -1)
90
+ if rope:
91
+ x = rope_rotate(x, x_positions * subsampling, *self.rotary(x))
92
+ return x.permute(0, 2, 1, 3)
93
+
94
+ def forward(
95
+ self,
96
+ qx,
97
+ q_positions,
98
+ kvx,
99
+ kv_positions,
100
+ causal = False,
101
+ mask=None,
102
+ ):
103
+ if self.k_cache is not None:
104
+ assert qx.shape[0] <= self.k_cache.shape[0], "please pass in a larger max_batch_size to setup_kv_cache"
105
+ if self.qkv:
106
+ q,k,v = self.qkv(qx).split(self.odim, dim=-1)
107
+ elif self.kv:
108
+ q = self.q(qx)
109
+ k,v = self.kv(kvx).split(self.odim, dim=-1)
110
+ else:
111
+ q,k,v = None,None,None
112
+
113
+ if q is None: q = self.query(qx) * self.sqrt_qk_scale
114
+ q = self.split_heads(q, q_positions, rope = self.rotary, subsampling = self.query_subsampling)
115
+
116
+ if kvx is not self.cached_kvx:
117
+ if k is None: k = self.key(kvx) * self.sqrt_qk_scale
118
+ k = self.split_heads(k, kv_positions, rope = self.rotary, subsampling = self.key_subsampling)
119
+ if v is None: v = self.value(kvx)
120
+ v = self.split_heads(v, kv_positions)
121
+ if self.k_cache is not None:
122
+ self.k_cache[:k.shape[0],:,kv_positions] = k
123
+ self.v_cache[:v.shape[0],:,kv_positions] = v
124
+
125
+ if self.k_cache is not None:
126
+ k, v = self.k_cache[:k.shape[0]], self.v_cache[:v.shape[0]]
127
+
128
+ if mask is not None:
129
+ mask = mask[q_positions,:k.shape[-2]]
130
+
131
+ wv = F.scaled_dot_product_attention(q, k, v, attn_mask=mask, dropout_p=0, is_causal=causal)
132
+
133
+ return self.out(wv.permute(0, 2, 1, 3).flatten(start_dim=2))
134
+
135
+ class Rotary(torch.nn.Module):
136
+ def __init__(self, dim, base=10000):
137
+ super().__init__()
138
+ inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))
139
+ self.register_buffer("inv_freq", inv_freq)
140
+ self.seq_len_cached = None
141
+ self.cos_cached = None
142
+ self.sin_cached = None
143
+
144
+ def forward(self, x, seq_dim=1):
145
+ seq_len = x.shape[seq_dim]
146
+ if not self.seq_len_cached or seq_len > self.seq_len_cached:
147
+ self.seq_len_cached = 2500
148
+
149
+ t = torch.arange(self.seq_len_cached, device=x.device).type_as(self.inv_freq)
150
+ freqs = torch.einsum("i,j->ij", t, self.inv_freq)
151
+ emb = torch.cat((freqs, freqs), dim=-1).to(x.device)
152
+ self.cos_cached = emb.cos()[None, :, None, :]
153
+ self.sin_cached = emb.sin()[None, :, None, :]
154
+ return self.cos_cached, self.sin_cached
155
+
156
+ def rotate_half(x):
157
+ x1, x2 = x[..., : x.shape[-1] // 2], x[..., x.shape[-1] // 2 :]
158
+ return torch.cat(
159
+ (-x2, x1), dim=len(x.shape)-1
160
+ )
161
+
162
+ def rope_rotate(x, positions, cos, sin):
163
+ return x * cos[:,positions] + rotate_half(x) * sin[:,positions]
164
+
165
+ class ResidualAttentionBlock(nn.Module):
166
+ def __init__(self, n_state: int, n_head: int, cross_attention: bool = False, rope: bool = False,
167
+ qk_scale: float = 1, ffn_mult: int = 4):
168
+ super().__init__()
169
+ self.attn = MultiHeadAttention(n_state, n_head, qk_scale=qk_scale, rope=rope)
170
+ self.attn_ln = LayerNorm(n_state)
171
+
172
+ self.cross_attn = (
173
+ MultiHeadAttention(n_state, n_head, qk_scale=qk_scale, rope=rope, cross=True) if cross_attention else None
174
+ )
175
+ self.cross_attn_ln = LayerNorm(n_state) if cross_attention else None
176
+
177
+ n_mlp = n_state * ffn_mult
178
+ self.mlp = nn.Sequential(
179
+ nn.Linear(n_state, n_mlp), nn.GELU(), nn.Linear(n_mlp, n_state)
180
+ )
181
+ self.mlp_ln = LayerNorm(n_state)
182
+
183
+ def setup_kv_cache(self, max_batch_size, max_seq_len, max_cross_seq_len=None):
184
+ self.attn.setup_kv_cache(max_batch_size, max_seq_len)
185
+ if self.cross_attn:
186
+ self.cross_attn.setup_kv_cache(max_batch_size, max_cross_seq_len)
187
+
188
+ def forward(
189
+ self,
190
+ x: Tensor,
191
+ x_positions: Tensor = None,
192
+ xa: Optional[Tensor] = None,
193
+ xa_positions: Optional[Tensor] = None,
194
+ causal = False,
195
+ mask=None,
196
+ ):
197
+ lnx = self.attn_ln(x)
198
+ x = x + self.attn(lnx, x_positions, lnx, x_positions, causal=causal, mask=mask)
199
+ if self.cross_attn:
200
+ lnx = self.cross_attn_ln(x)
201
+ x = x + self.cross_attn(lnx, x_positions, xa, xa_positions)
202
+ x = x + self.mlp(self.mlp_ln(x))
203
+ return x
204
+
205
+ class BaseDecoder(nn.Module):
206
+ def __init__(self, depth=6, n_head=6, width=384, qk_scale=1, ffn_mult=4, length=2250, rope=False):
207
+ super().__init__()
208
+ self.length = length
209
+ self.width = width
210
+ self.layers = nn.ModuleList([
211
+ ResidualAttentionBlock(
212
+ self.width, n_head, qk_scale=qk_scale, ffn_mult=ffn_mult, cross_attention=True, rope=rope
213
+ ) for _ in range(math.floor(depth))
214
+ ])
215
+
216
+ self.ln_post = LayerNorm(width)
217
+
218
+ mask = torch.empty(length, length).fill_(-torch.inf).triu_(1)
219
+ self.register_buffer("mask", mask, persistent=False)
220
+
221
+ def forward(self, x, x_positions, xenc, xenc_positions):
222
+ for i,l in enumerate(self.layers):
223
+ x = l(x, x_positions, xenc, xenc_positions, causal=self.training, mask=self.mask if not self.training else None)
224
+
225
+ x = self.ln_post(x)
226
+
227
+ return x
228
+
229
+ class EmbeddingProjector(nn.Linear):
230
+ pass
231
+
232
+ class FlexEmbeddings(nn.Module):
233
+ def __init__(self, codes, width, special_codes=None, frozen_width=None, special_embedding=None, unembed=True):
234
+ super().__init__()
235
+ self.codes = codes
236
+ self.special_codes = special_codes
237
+ if frozen_width is None: frozen_width = width
238
+
239
+ self.main = nn.Embedding(codes, frozen_width or width)
240
+ self.emb_to_hidden = EmbeddingProjector(frozen_width, width) if frozen_width != width else None
241
+ self.hidden_to_emb = EmbeddingProjector(width, frozen_width) if unembed and frozen_width != width else None
242
+ if special_codes:
243
+ self.special = special_embedding or nn.Embedding(special_codes, width)
244
+
245
+ self.register_buffer('merged_in', None)
246
+ self.register_buffer('merged_out', None)
247
+ self.register_buffer('bias_out', None)
248
+
249
+ def set_frozen_embeddings(self, values):
250
+ with torch.no_grad():
251
+ self.main.weight[:] = values
252
+ self.main.lr_scale = 0
253
+
254
+ @torch.no_grad()
255
+ def convert_for_eval(self):
256
+ if not self.special_codes: return
257
+ main_w = self.main.weight
258
+ if self.emb_to_hidden is not None: main_w = self.emb_to_hidden(main_w)
259
+ weight = torch.cat([main_w, self.special.weight], dim=0)
260
+ self.merged_in = nn.Embedding(*weight.shape, _weight=weight)
261
+
262
+ weight = self.main.weight
263
+ if self.hidden_to_emb: weight = weight @ self.hidden_to_emb.weight
264
+ self.merged_out = torch.cat([weight.T, self.special.weight.T], dim=1).T.contiguous()
265
+ if self.hidden_to_emb:
266
+ self.bias_out = torch.cat([
267
+ self.hidden_to_emb.bias @ self.main.weight.T,
268
+ torch.zeros(self.special.weight.shape[0], device=weight.device, dtype=weight.dtype)
269
+ ], dim=0)
270
+ else:
271
+ self.bias_out = None
272
+
273
+ def forward(self, toks):
274
+ if not self.training and self.merged_in is not None:
275
+ return self.merged_in(toks)
276
+
277
+ if self.special_codes:
278
+ special_mask = toks >= self.codes
279
+ embs = self.main(torch.where(special_mask, 0, toks))
280
+ else:
281
+ embs = self.main(toks)
282
+
283
+ if self.emb_to_hidden: embs = self.emb_to_hidden(embs)
284
+
285
+ if self.special_codes:
286
+ embs[special_mask] = self.special(toks[special_mask] - self.codes).to(embs.dtype)
287
+
288
+ return embs
289
+
290
+ def unembed(self, embs):
291
+ if not self.training and self.merged_out is not None:
292
+ return F.linear(embs, self.merged_out, self.bias_out)
293
+
294
+ orig_embs = embs
295
+ if self.hidden_to_emb: embs = self.hidden_to_emb(embs)
296
+
297
+ main_logits = (embs @ self.main.weight.to(embs.dtype).T).float()
298
+
299
+ if not self.special_codes:
300
+ return main_logits
301
+
302
+ special_logits = (orig_embs @ self.special.weight.to(orig_embs.dtype).T).float()
303
+ return torch.cat([main_logits, special_logits], dim=-1)
@@ -0,0 +1,107 @@
1
+ from os.path import expanduser
2
+ import torch
3
+ from whisperspeech2.t2s_up_wds_mlang_enclm import TSARTransformer
4
+ from whisperspeech2.s2a_delar_mup_wds_mlang import SADelARTransformer
5
+ from whisperspeech2.a2wav import Vocoder
6
+ from whisperspeech2 import inference, s2a_delar_mup_wds_mlang_cond
7
+ import traceback
8
+ from pathlib import Path
9
+
10
+ __all__ = ['Pipeline']
11
+
12
+ class Pipeline:
13
+ default_speaker = torch.tensor(
14
+ [-0.2929, -0.4503, 0.4155, -0.1417, 0.0473, -0.1624, -0.2322, 0.7071,
15
+ 0.4800, 0.5496, 0.0410, 0.6236, 0.4729, 0.0587, 0.2194, -0.0466,
16
+ -0.3036, 0.0497, 0.5028, -0.1703, 0.5039, -0.6464, 0.3857, -0.7350,
17
+ -0.1605, 0.4808, 0.5397, -0.4851, 0.1774, -0.8712, 0.5789, 0.1785,
18
+ -0.1417, 0.3039, 0.4232, -0.0186, 0.2685, 0.6153, -0.3103, -0.5706,
19
+ -0.4494, 0.3394, -0.6184, -0.3617, 1.1041, -0.1178, -0.1885, 0.1997,
20
+ 0.5571, -0.2906, -0.0477, -0.4048, -0.1062, 1.4779, 0.1639, -0.3712,
21
+ -0.1776, -0.0568, -0.6162, 0.0110, -0.0207, -0.1319, -0.3854, 0.7248,
22
+ 0.0343, 0.5724, 0.0670, 0.0486, -0.3813, 0.1738, 0.3017, 1.0502,
23
+ 0.1550, 0.5708, 0.0366, 0.5093, 0.0294, -0.7091, -0.8220, -0.1583,
24
+ -0.2343, 0.1366, 0.7372, -0.0631, 0.1505, 0.4600, -0.1252, -0.5245,
25
+ 0.7523, -0.0386, -0.2587, 1.0066, -0.2037, 0.1617, -0.3800, 0.2790,
26
+ 0.0184, -0.5111, -0.7291, 0.1627, 0.2367, -0.0192, 0.4822, -0.4458,
27
+ 0.1457, -0.5884, 0.1909, 0.2563, -0.2035, -0.0377, 0.7771, 0.2139,
28
+ 0.3801, 0.6047, -0.6043, -0.2563, -0.0726, 0.3856, 0.3217, 0.0823,
29
+ -0.1302, 0.3287, 0.5693, 0.2453, 0.8231, 0.0072, 1.0327, 0.6065,
30
+ -0.0620, -0.5572, 0.5220, 0.2485, 0.1520, 0.0222, -0.2179, -0.7392,
31
+ -0.3855, 0.1822, 0.1042, 0.7133, 0.3583, 0.0606, -0.0424, -0.9189,
32
+ -0.4882, -0.5480, -0.5719, -0.1660, -0.3439, -0.5814, -0.2542, 0.0197,
33
+ 0.4942, 0.0915, -0.0420, -0.0035, 0.5578, 0.1051, -0.0891, 0.2348,
34
+ 0.6876, -0.6685, 0.8215, -0.3692, -0.3150, -0.0462, -0.6806, -0.2661,
35
+ -0.0308, -0.0050, 0.6756, -0.1647, 1.0734, 0.0049, 0.4969, 0.0259,
36
+ -0.8949, 0.0731, 0.0886, 0.3442, -0.1433, -0.6804, 0.2204, 0.1859,
37
+ 0.2702, 0.1699, -0.1443, -0.9614, 0.3261, 0.1718, 0.3545, -0.0686]
38
+ )
39
+
40
+ def __init__(self, t2s_ref=None, s2a_ref=None, optimize=True, torch_compile=False, device=None, cache_dir=None):
41
+ if device is None: device = inference.get_compute_device()
42
+ self.device = device
43
+ args = dict(device = device, cache_dir=cache_dir)
44
+ try:
45
+ if t2s_ref:
46
+ args["ref"] = t2s_ref
47
+ self.t2s = TSARTransformer.load_model(**args)
48
+ if optimize: self.t2s.optimize(torch_compile=torch_compile)
49
+ except:
50
+ print("Failed to load the T2S model:")
51
+ print(traceback.format_exc())
52
+ args = dict(device = device, cache_dir=cache_dir)
53
+ try:
54
+ if s2a_ref:
55
+ spec = inference.load_model(ref=s2a_ref, device=device, cache_dir=cache_dir)
56
+ if [x for x in spec['state_dict'].keys() if x.startswith('cond_embeddings.')]:
57
+ cls = s2a_delar_mup_wds_mlang_cond.SADelARTransformer
58
+ args['spec'] = spec
59
+ else:
60
+ cls = SADelARTransformer
61
+ args['spec'] = spec
62
+ else:
63
+ cls = SADelARTransformer
64
+ self.s2a = cls.load_model(**args)
65
+ if optimize: self.s2a.optimize(torch_compile=torch_compile)
66
+ except:
67
+ print("Failed to load the S2A model:")
68
+ print(traceback.format_exc())
69
+
70
+ self.vocoder = Vocoder(device=device)
71
+ self.encoder = None
72
+
73
+ def extract_spk_emb(self, fname):
74
+ import torchaudio
75
+ if self.encoder is None:
76
+ device = self.device
77
+ if device == 'mps': device = 'cpu'
78
+ from speechbrain.pretrained import EncoderClassifier
79
+ self.encoder = EncoderClassifier.from_hparams("speechbrain/spkrec-ecapa-voxceleb",
80
+ savedir=expanduser("~/.cache/speechbrain/"),
81
+ run_opts={"device": device})
82
+ audio_info = torchaudio.info(fname)
83
+ actual_sample_rate = audio_info.sample_rate
84
+ num_frames = actual_sample_rate * 30
85
+ samples, sr = torchaudio.load(fname, num_frames=num_frames)
86
+ samples = samples[:, :num_frames]
87
+ samples = self.encoder.audio_normalizer(samples[0], sr)
88
+ spk_emb = self.encoder.encode_batch(samples.unsqueeze(0))
89
+
90
+ return spk_emb[0,0].to(self.device)
91
+
92
+ def generate_atoks(self, text, speaker=None, lang='en', cps=15, step_callback=None):
93
+ if speaker is None: speaker = self.default_speaker
94
+ elif isinstance(speaker, (str, Path)): speaker = self.extract_spk_emb(speaker)
95
+ text = text.replace("\n", " ")
96
+ stoks = self.t2s.generate(text, cps=cps, lang=lang, step=step_callback)[0]
97
+ atoks = self.s2a.generate(stoks, speaker.unsqueeze(0), step=step_callback)
98
+ return atoks
99
+
100
+ def generate(self, text, speaker=None, lang='en', cps=15, step_callback=None):
101
+ return self.vocoder.decode(self.generate_atoks(text, speaker, lang=lang, cps=cps, step_callback=step_callback))
102
+
103
+ def generate_to_file(self, fname, text, speaker=None, lang='en', cps=15, step_callback=None):
104
+ self.vocoder.decode_to_file(fname, self.generate_atoks(text, speaker, lang=lang, cps=cps, step_callback=None))
105
+
106
+ def generate_to_notebook(self, text, speaker=None, lang='en', cps=15, step_callback=None):
107
+ self.vocoder.decode_to_notebook(self.generate_atoks(text, speaker, lang=lang, cps=cps, step_callback=None))
@@ -0,0 +1,8 @@
1
+ from whisperspeech2.pipeline import Pipeline
2
+
3
+ tts_pipe = Pipeline(s2a_ref='collabora/whisperspeech:s2a-q4-tiny-en+pl.model') # uncomment the line for the model you want to use
4
+ # tts_pipe = Pipeline(s2a_ref='collabora/whisperspeech:s2a-q4-base-en+pl.model') # uncomment the line for the model you want to use
5
+ # tts_pipe = Pipeline(s2a_ref='collabora/whisperspeech:s2a-q4-small-en+pl.model') # uncomment the line for the model you want to use
6
+
7
+ save_path = 'output.wav' # change the file extension to .mp3, .flac, .ogg etc. to save to a different file format
8
+ tts_pipe.generate_to_file(save_path, "This is a test")