Views
No views yet
1from huggingface_hub import hf_hub_download
2import soundfile
3import torch
4from transformers import Wav2Vec2PreTrainedModel, PretrainedConfig
5from torch import nn
6import torch.nn.functional as F
7
8
9
10class Voc(Wav2Vec2PreTrainedModel):
11
12 '''For using different batch_siz -> Voc._flush()
13 '''
14
15 def __init__(self, config=PretrainedConfig()):
16 super().__init__(config=config)
17 self.encoder_transformer = VocTransformer()
18 self.decoder_transformer = VocTransformer()
19 self.encoder = SEANetEncoder()
20 self.decoder = SEANetDecoder()
21 self.sample_rate = 24000
22 self.quantizer = SplitResidualVectorQuantizer()
23 self.downsample = BufferConv1d(512, 512, kernel_size=4, stride=2, groups=1, bias=False)
24 upsample_channel_wise_bug = True
25 self.upsample = BufferConvTranspose1d(512, 512, kernel_size=4,
26 groups=512 if upsample_channel_wise_bug else 1,
27 stride=2, bias=False)
28 self.frame_rate = 12.5
29 self.encode_buffer = None
30
31 def _flush(self):
32 '''stream buffers have tensors of old batch size! Voc()._flush() to clean buffers
33 '''
34 self.encode_buffer = None # holds unused (incomplete windows of len < 1920) - we need 1920 to produce 1 token
35 if self.downsample.previous is not None:
36 self.downsample.previous = None
37 if self.upsample.partial is not None:
38 self.upsample.partial = None
39 for arch in [self.encoder, self.decoder]:
40 for _m in arch.model:
41 if type(_m) is SEANetResnetBlock:
42 for _b in _m.block:
43 if type(_b) is BufferConv1d:
44 if _b.previous is not None:
45 _b.previous = None
46 if type(_m) is BufferConv1d:
47 if _m.previous is not None:
48 _m.previous = None
49 if type(_m) is BufferConvTranspose1d:
50 if _m.partial is not None:
51 _m.partial = None
52
53 @torch.no_grad()
54 def encode(self, x):
55 '''24KHz audio to codes
56 x : [bs, 1, 24 KHz]
57 c : [bs, 8, time] = 1920 audio samples produce 1 time frame (of n_q codebooks)
58 '''
59 if self.encode_buffer is not None:
60 x = torch.cat([self.encode_buffer, x], 2)
61 _bs, _1, _len = x.shape
62 num_frames = int(_len / 1920)
63 leftover = x[:, :, (num_frames+1) * 1920:]
64 if leftover.shape[2] > 0:
65 self.encode_buffer = leftover
66 else:
67 self.encode_buffer = None
68 torch.cuda.empty_cache()
69 if num_frames > 0:
70 c = []
71 for n in range(num_frames):
72 e = self.encoder(x[:, :, n * 1920:(n + 1) * 1920])
73 e = self.encoder_transformer(e)
74 e = self.downsample(e)
75 _c = self.quantizer.encode(e)
76 c.append(_c)
77 c = torch.cat(c, 2)
78 else:
79 # num_frames = 0 Early exit -> for x.shape[2]<1920 fill conv buffers but can't output token
80 c = torch.empty(_bs, 0, self.n_q)
81 return c
82
83 @torch.no_grad()
84 def decode(self, c):
85 '''codes to 24kHZ audio
86 c: [bs, 8, n_tokens]
87 x: [bs, 1, n_tokens * 1920]
88 '''
89 _hidden = []
90 for i in range(c.shape[2]):
91 x = self.quantizer.decode(c[:, :, i:i+1])
92 x = self.upsample(x)
93 x = self.decoder_transformer(x)
94 x = self.decoder(x)
95 _hidden.append(x)
96 return torch.cat(_hidden, 2) # [bs, 1, 24KHz]
97
98
99class SEANetResnetBlock(nn.Module):
100 def __init__(
101 self,
102 dim,
103 kernel_sizes=[3, 1],
104 ):
105 super().__init__()
106
107 block = []
108 for i, kernel_size in enumerate(kernel_sizes):
109
110 block += [
111 nn.ELU(),
112 BufferConv1d(
113 dim if i == 0 else dim // 2,
114 dim // 2 if i == 0 else dim,
115 kernel_size=kernel_size,
116 bias=True,
117 ),
118 ]
119
120 self.block = nn.Sequential(*block)
121
122 def forward(self, x):
123 return x + self.block(x)
124
125
126class SEANetEncoder(nn.Module):
127 def __init__(
128 self,
129 channels=1, # DOES NOT SUPPORT STEREO
130 dimension=512,
131 n_filters=64,
132 ratios=[8, 6, 5, 4],
133 kernel_size=7,
134 last_kernel_size=3,
135 ):
136 super().__init__()
137 self.ratios = list(reversed(ratios))
138 del ratios
139 mult = 1
140 model=[
141 BufferConv1d(
142 channels,
143 mult * n_filters,
144 kernel_size,
145 bias=True
146 )
147 ]
148 for i, ratio in enumerate(self.ratios):
149 model += [SEANetResnetBlock(mult * n_filters),
150 nn.ELU(),
151 BufferConv1d(mult * n_filters,
152 mult * n_filters * 2,
153 kernel_size=ratio * 2,
154 stride=ratio,
155 bias=True)]
156 mult *= 2
157 # ENDFOR
158 model += [nn.ELU(),
159 BufferConv1d(mult * n_filters,
160 dimension,
161 last_kernel_size,
162 bias=True)]
163 self.model = nn.Sequential(*model)
164
165 def forward(self, x):
166 return self.model(x)
167
168
169class SEANetDecoder(nn.Module):
170
171 def __init__(
172 self,
173 channels=1,
174 dimension=512,
175 n_filters=64,
176 ratios=[8, 6, 5, 4],
177 kernel_size=7,
178 last_kernel_size=3):
179
180 super().__init__()
181 mult = int(2 ** len(ratios))
182 model = [BufferConv1d(dimension,
183 mult * n_filters,
184 kernel_size,
185 bias=True)]
186 #UP
187 for i, ratio in enumerate(ratios):
188 model += [nn.ELU(),
189 BufferConvTranspose1d(mult * n_filters,
190 mult * n_filters // 2,
191 kernel_size=ratio * 2,
192 stride=ratio,
193 bias=True),
194 SEANetResnetBlock(mult * n_filters // 2)]
195 mult //= 2
196 # LAST
197 model += [
198 nn.ELU(),
199 BufferConv1d(
200 n_filters,
201 channels,
202 last_kernel_size,
203 bias=True
204 ),
205 ]
206 self.model = nn.Sequential(*model)
207
208 def forward(self, x):
209 return self.model(x)
210
211
212class BufferConv1d(nn.Conv1d):
213 def __init__(self,
214 *args,
215 **kwargs):
216 super().__init__(*args, **kwargs)
217 self.previous = None
218
219 def forward(self, x):
220 k = self.kernel_size[0]
221
222 if self.previous is not None:
223
224 x = torch.cat([self.previous, x], 2)
225
226 else: # If self.previous is None => Use zero pad
227
228 if k == 3:
229
230 p = (2, 0)
231 x = F.pad(x, p, mode='replicate', value=0.0) # skip connections SeaNetResBlk
232
233 elif k == 4: # ConvTrUpsample is the first conv encountered by decode replicate solves pulse
234
235 p = (3, 0)
236 x = F.pad(x, p, mode='replicate', value=0.0)
237
238 elif k == 7:
239
240 p = (6, 0)
241 x = F.pad(x, p, mode='replicate', value=0.0)
242
243 elif k == 16:
244
245 p = (2, 0)
246 x = F.pad(x, p, mode='replicate', value=0.0) # THis can be also constant w/o pulse occur
247
248 num_frames = int( (x.shape[2] - self.kernel_size[0]) / self.stride[0] ) + 1 # +1 is: k starts at left of x and doing (I-k)/s jumps
249 offset = num_frames * self.stride[0]
250 self.previous = x[..., offset:]
251 return super().forward(x)
252
253
254class BufferConvTranspose1d(nn.ConvTranspose1d):
255 # kernel 5 has only 1 pixel for input (cloned)
256 # https://distill.pub/2016/deconv-checkerboard/
257 def __init__(self,
258 *args,
259 **kwargs):
260 super().__init__(*args,
261 **kwargs)
262 self.partial = None
263
264 def forward(self, x):
265 out = super().forward(x)
266 OT = out.shape[2]
267 invalid_steps = self.kernel_size[0] - self.stride[0]
268 if self.partial is not None:
269 PT = self.partial.shape[-1]
270 if self.bias is not None:
271 out[..., :PT] += self.partial - self.bias[:, None]
272 else:
273 out[..., :PT] += self.partial # for ConvTrUpsample1d
274 invalid_steps = self.kernel_size[0] - self.stride[0]
275 self.partial = out[..., OT - invalid_steps :]
276 out = out[...,:OT - invalid_steps]
277 return out
278
279
280class CodeBook(nn.Module):
281 def __init__(self, dim, codebook_size):
282 super().__init__()
283 self.register_buffer('_e', torch.zeros(codebook_size, dim))
284
285 def encode(self, x):
286 dist = torch.cdist(
287 x.transpose(1, 2), # [bs, time, 256]
288 self._e[None, :, :] # [1, 2048, 256]
289 )
290 codes = dist.argmin(2)
291 return codes
292
293 def decode(self, codes):
294 quantized = F.embedding(codes, self._e)
295 return quantized.transpose(1, 2) # [1, 256, time]
296
297
298class SplitResidualVectorQuantizer(nn.Module):
299
300 def __init__(self,
301 n_q=None):
302 super().__init__()
303 self.in_proj_s = torch.nn.Conv1d(512, 256, 1, bias=False)
304 self.in_proj_a = torch.nn.Conv1d(512, 256, 1, bias=False)
305 self.out_proj_s = torch.nn.Conv1d(256, 512, 1, bias=False) # reused for all _acoustic_books
306 self.out_proj_a = torch.nn.Conv1d(256, 512, 1, bias=False)
307 self.layers = nn.ModuleList([CodeBook(dim=256, codebook_size=2048) for _ in range(18)])
308 # self._acoustic_books = range(1, 16) # Official Mimi
309 # CODE BOOKS
310 # Here we re use RVQ codebooks for higher fidelity!
311 # Exclude 0 here as it has different proj (in_proj_s)
312 self._acoustic_books = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 17, 17, 17, 17]
313
314 def encode(self, x):
315 indices = self.layers[0].encode(self.in_proj_s(x)) # integers
316 all_indices = [ indices[:, None, :], ]
317 x = self.in_proj_a(x)
318 for _cb in self._acoustic_books:
319 indices = self.layers[_cb].encode(x)
320 x = x - self.layers[_cb].decode(indices)
321 all_indices.append(indices[:, None, :])
322 codes = torch.cat(all_indices, 1)
323 return codes
324
325 def decode(self, codes):
326 _s = self.layers[0].decode(codes[:, 0, :])
327 _a = torch.zeros([1, 1], device=codes.device)
328 for i, _cb in enumerate(self._acoustic_books):
329 _a = _a + self.layers[_cb].decode(codes[:, i+1, :])
330 return self.out_proj_s(_s) + self.out_proj_a(_a) # [bs, 512, time]
331
332
333class VocAttention(nn.Module):
334
335 def __init__(self,
336 embed_dim):
337
338 super().__init__()
339 self.fused_proj = nn.Parameter(torch.zeros(embed_dim, embed_dim))
340
341 def forward(self, x):
342 '''bypass of streaming training'''
343 if x.shape[1] > 1:
344 x = x.mean(1, keepdims=True)
345 x = torch.matmul(x, self.fused_proj)
346 return x # FFN broadcasts to x.shape[1]=2
347
348
349class VocTransformerLayer(nn.Module):
350
351 def __init__(self, d_model=512, dim_feedforward=2048):
352 super().__init__()
353 self.self_attn = VocAttention(embed_dim=d_model)
354 self.norm1 = nn.LayerNorm(d_model, eps=1e-5)
355 self.norm2 = nn.LayerNorm(d_model, eps=1e-5)
356 self.linear1 = nn.Linear(d_model, dim_feedforward, bias=False)
357 self.linear2 = nn.Linear(dim_feedforward, d_model, bias=False)
358
359 def forward(self, x):
360 x = x + self.self_attn(self.norm1(x))
361 return x + self.linear2(F.gelu(self.linear1(self.norm2(x))))
362
363
364class VocTransformer(nn.Module):
365
366 def __init__(self):
367
368 super().__init__()
369 self.layers = nn.ModuleList(VocTransformerLayer() for _ in range(8))
370
371 def forward(self, x):
372 x = x.transpose(1, 2)
373 for la in self.layers:
374 x = la(x)
375 return x.transpose(1, 2)
376
377device = 'cpu' #'cuda:0'
378model = Voc.from_pretrained('ivao0/voc').to(device)
379x, _ = soundfile.read(hf_hub_download(repo_id='ivao0/voc', filename='true.wav')) # 24 KHz
380x = torch.from_numpy(x[None, None, :]).to(dtype=torch.float, device=device)
381codes = model.encode(x) # [bs, len(_acoustic_books) + 1, T]
382y = model.decode(codes) # audio signal 24KHz
383soundfile.write('reconstruct.wav', y[0, 0, :].cpu().numpy(), 24000)
384model._flush() # For encode()/decode() for different batch size
385