0hawkeye33 commited on
Commit
cc2cb10
·
verified ·
1 Parent(s): 04d4e14

Create GenerateAudios.py

Browse files
Files changed (1) hide show
  1. ISMIR/Adapters_40M/GenerateAudios.py +373 -0
ISMIR/Adapters_40M/GenerateAudios.py ADDED
@@ -0,0 +1,373 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torchaudio
4
+ from transformers import AutoProcessor, MusicgenForConditionalGeneration
5
+ import os
6
+ import matplotlib.pyplot as plt
7
+ import pandas as pd
8
+
9
+ # Paths and configurations
10
+ pretrained_model_name = "facebook/musicgen-medium" # Pre-trained MusicGen model name
11
+ model_save_path = r"/home/shivam.chauhan/.cache/huggingface/hub/models--0hawkeye33--Adapters/blobs/95d3c77dc73bd989622740c3ed49c13af31fccae5a1b507ca75fda0fa5aba091" # Path to the fine-tuned model
12
+ sample_rate = 32000 # Desired sample rate for the output audio
13
+ adapter_bottleneck_dim = 512 # Use the same dimension as training, use 612 for linear
14
+ max_new_tokens = 1024 # To control length of music piece generated 512 = 10 sec
15
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
16
+
17
+ # Configuration to choose between pre-trained and fine-tuned model
18
+ use_finetuned_model = True # Set to True to use the fine-tuned model, False to use pre-trained model
19
+
20
+
21
+
22
+
23
+ """
24
+ #################################### Linear Adapter class Begins here ############################
25
+ class Adapter(nn.Module):
26
+ def __init__(self, bottleneck_channels=256, input_channels=1, seq_len=32000):
27
+ super(Adapter, self).__init__()
28
+ self.adapter_down = nn.Linear(seq_len, bottleneck_channels)
29
+ self.activation = nn.ReLU()
30
+ self.adapter_up = nn.Linear(bottleneck_channels, seq_len)
31
+ self.dropout = nn.Dropout(p=0.0)
32
+
33
+ def forward(self, residual):
34
+ x = self.adapter_down(residual.squeeze(1))
35
+ x = self.activation(x)
36
+ x = self.adapter_up(x)
37
+ x = self.dropout(x + residual.squeeze(1))
38
+ return x.unsqueeze(1)
39
+
40
+ # MusicGen Model with Adapter (same as in training)
41
+ class MusicGenWithAdapters(nn.Module):
42
+ def __init__(self, musicgen_model, processor, adapter_bottleneck_dim=256, device='cpu'):
43
+ super(MusicGenWithAdapters, self).__init__()
44
+ self.musicgen = musicgen_model
45
+ self.adapter = Adapter(bottleneck_channels=adapter_bottleneck_dim, input_channels=2, seq_len=32000).to(device)
46
+
47
+ def forward(self, audio_text):
48
+ encoder_output = self.musicgen.generate(**audio_text, max_new_tokens=max_new_tokens)
49
+ encoder_output = encoder_output.to('cpu')
50
+ encoder_output = torchaudio.transforms.Resample(orig_freq=encoder_output.size(2), new_freq=32000)(encoder_output)
51
+ encoder_output = encoder_output.to(self.adapter.adapter_down.weight.device)
52
+ adapted = self.adapter(encoder_output)
53
+ return adapted
54
+
55
+ #################################### Linear Adapter class Ends here ############################
56
+ """
57
+
58
+
59
+
60
+
61
+
62
+ #################################### CNN Adapter class Begins here ############################
63
+ class Adapter(nn.Module):
64
+ def __init__(self, bottleneck_channels=192, input_channels=2, seq_len=32000, dropout_prob=0.1):
65
+ super(Adapter, self).__init__()
66
+
67
+ # Adapter Down: change kernel size from 5 to 7 (with padding=3 to maintain seq_len)
68
+ self.adapter_down = nn.Sequential(
69
+ nn.Conv1d(
70
+ in_channels=input_channels,
71
+ out_channels=bottleneck_channels,
72
+ kernel_size=7, # changed from 5 to 7
73
+ stride=1,
74
+ padding=3 # adjusted for kernel_size=7
75
+ ),
76
+ nn.BatchNorm1d(bottleneck_channels),
77
+ nn.GELU()
78
+ )
79
+
80
+ # Bottleneck: use 8 ResidualBlocks (each with kernel_size=7) instead of 6.
81
+ self.bottleneck = nn.Sequential(
82
+ ResidualBlock(bottleneck_channels, bottleneck_channels, kernel_size=7, dilation=1),
83
+ ResidualBlock(bottleneck_channels, bottleneck_channels, kernel_size=7, dilation=2),
84
+ ResidualBlock(bottleneck_channels, bottleneck_channels, kernel_size=7, dilation=4),
85
+ ResidualBlock(bottleneck_channels, bottleneck_channels, kernel_size=7, dilation=8),
86
+ ResidualBlock(bottleneck_channels, bottleneck_channels, kernel_size=7, dilation=16),
87
+ ResidualBlock(bottleneck_channels, bottleneck_channels, kernel_size=7, dilation=32),
88
+ ResidualBlock(bottleneck_channels, bottleneck_channels, kernel_size=7, dilation=64),
89
+ ResidualBlock(bottleneck_channels, bottleneck_channels, kernel_size=7, dilation=128),
90
+ ResidualBlock(bottleneck_channels, bottleneck_channels, kernel_size=7, dilation=256),
91
+ # Two extra ResidualBlocks to increase depth and parameters:
92
+ ResidualBlock(bottleneck_channels, bottleneck_channels, kernel_size=7, dilation=1),
93
+ ResidualBlock(bottleneck_channels, bottleneck_channels, kernel_size=7, dilation=2),
94
+ SEBlock(bottleneck_channels),
95
+ nn.Conv1d(bottleneck_channels, bottleneck_channels, kernel_size=3, stride=1, padding=1),
96
+ nn.BatchNorm1d(bottleneck_channels),
97
+ nn.GELU(),
98
+ )
99
+
100
+ # Adapter Up: also change kernel size from 5 to 7 (with padding=3)
101
+ self.adapter_up = nn.Sequential(
102
+ nn.Conv1d(
103
+ in_channels=bottleneck_channels,
104
+ out_channels=input_channels,
105
+ kernel_size=7, # changed from 5 to 7
106
+ stride=1,
107
+ padding=3 # adjusted for kernel_size=7
108
+ ),
109
+ nn.BatchNorm1d(input_channels)
110
+ )
111
+
112
+ self.dropout = nn.Dropout(p=dropout_prob)
113
+
114
+ def forward(self, residual):
115
+ x = self.adapter_down(residual)
116
+ x = self.bottleneck(x)
117
+ x = self.adapter_up(x)
118
+ x = self.dropout(x + residual) # residual connection
119
+ return x
120
+
121
+ class ResidualBlock(nn.Module):
122
+ def __init__(self, in_channels, out_channels, kernel_size=7, stride=1, dilation=1):
123
+ super(ResidualBlock, self).__init__()
124
+
125
+ # The larger kernel size increases parameter count.
126
+ self.conv1 = nn.Conv1d(
127
+ in_channels, out_channels, kernel_size, stride,
128
+ padding=(kernel_size // 2) * dilation, dilation=dilation
129
+ )
130
+ self.bn1 = nn.BatchNorm1d(out_channels)
131
+ self.activation = nn.GELU()
132
+
133
+ self.conv2 = nn.Conv1d(
134
+ out_channels, out_channels, kernel_size, stride,
135
+ padding=(kernel_size // 2) * dilation, dilation=dilation
136
+ )
137
+ self.bn2 = nn.BatchNorm1d(out_channels)
138
+
139
+ self.layer_norm = nn.LayerNorm(out_channels)
140
+
141
+ def forward(self, x):
142
+ residual = x # Preserve input for the skip connection
143
+ x = self.conv1(x)
144
+ x = self.bn1(x)
145
+ x = self.activation(x)
146
+ x = self.conv2(x)
147
+ x = self.bn2(x)
148
+ x = x + residual # Skip connection
149
+ return x
150
+
151
+ class SEBlock(nn.Module):
152
+ def __init__(self, channels, reduction=8):
153
+ super(SEBlock, self).__init__()
154
+ self.global_avg_pool = nn.AdaptiveAvgPool1d(1) # Squeeze
155
+ self.fc = nn.Sequential(
156
+ nn.Linear(channels, channels // reduction),
157
+ nn.ReLU(),
158
+ nn.Linear(channels // reduction, channels),
159
+ nn.Sigmoid()
160
+ )
161
+
162
+ def forward(self, x):
163
+ batch_size, channels, _ = x.shape
164
+ y = self.global_avg_pool(x).view(batch_size, channels)
165
+ y = self.fc(y).view(batch_size, channels, 1)
166
+ return x * y # Scale input features based on channel attention
167
+
168
+
169
+ # MusicGen Model with Adapter (same as in training)
170
+ class MusicGenWithAdapters(nn.Module):
171
+ def __init__(self, musicgen_model, processor, adapter_bottleneck_dim=256, device='cpu'):
172
+ super(MusicGenWithAdapters, self).__init__()
173
+ self.musicgen = musicgen_model
174
+ self.adapter = Adapter(bottleneck_channels=adapter_bottleneck_dim, input_channels=2, seq_len=32000).to(device)
175
+
176
+ def forward(self, audio_text):
177
+ encoder_output = self.musicgen.generate(**audio_text, max_new_tokens=max_new_tokens)
178
+ encoder_output = encoder_output.to('cpu')
179
+ encoder_output = torchaudio.transforms.Resample(orig_freq=encoder_output.size(2), new_freq=32000)(encoder_output)
180
+ encoder_output = encoder_output.to(self.adapter.adapter_down.weight.device)
181
+ adapted = self.adapter(encoder_output)
182
+ return adapted
183
+
184
+ #################################### CNN Adapter class Ends here ############################
185
+
186
+
187
+
188
+
189
+
190
+
191
+
192
+
193
+ """
194
+ #################################### Transformer Adapter class Begins here ############################
195
+ class TransformerAdapter(nn.Module):
196
+ def __init__(self, input_dim=32000, bottleneck_dim=1024, num_heads=4, ff_dim=512, dropout_prob=0.1):
197
+ super(TransformerAdapter, self).__init__()
198
+ # Project input to a lower dimension.
199
+ self.down_proj = nn.Linear(input_dim, bottleneck_dim)
200
+ # Multi-head self-attention.
201
+ self.attn = nn.MultiheadAttention(embed_dim=bottleneck_dim, num_heads=num_heads, dropout=dropout_prob)
202
+ # Layer normalization before attention.
203
+ self.ln1 = nn.LayerNorm(bottleneck_dim)
204
+ # Feed-forward network.
205
+ self.ffn = nn.Sequential(
206
+ nn.Linear(bottleneck_dim, ff_dim),
207
+ nn.GELU(),
208
+ nn.Linear(ff_dim, bottleneck_dim),
209
+ nn.Dropout(dropout_prob)
210
+ )
211
+ self.ln2 = nn.LayerNorm(bottleneck_dim)
212
+ # Project back to the original dimension.
213
+ self.up_proj = nn.Linear(bottleneck_dim, input_dim)
214
+ self.dropout = nn.Dropout(dropout_prob)
215
+
216
+ def forward(self, x):
217
+ # x: (batch_size, channels, seq_len)
218
+ batch_size, channels, seq_len = x.size()
219
+ # Flatten channels into the batch dimension.
220
+ x = x.reshape(batch_size * channels, seq_len) # Use reshape instead of view.
221
+ x = self.down_proj(x) # (B * channels, bottleneck_dim)
222
+ # Add a sequence dimension for attention.
223
+ x = x.unsqueeze(0) # (1, B * channels, bottleneck_dim)
224
+ attn_out, _ = self.attn(x, x, x)
225
+ x = x + attn_out # Residual connection.
226
+ x = self.ln1(x)
227
+ # Remove the sequence dimension.
228
+ x = x.squeeze(0) # (B * channels, bottleneck_dim)
229
+ ffn_out = self.ffn(x)
230
+ x = x + ffn_out # Residual connection.
231
+ x = self.ln2(x)
232
+ x = self.up_proj(x)
233
+ x = self.dropout(x)
234
+ # Restore the original shape.
235
+ return x.reshape(batch_size, channels, seq_len) # Use reshape here as well.
236
+
237
+
238
+
239
+ # MusicGen Model with Adapter for Transformer
240
+ class MusicGenWithAdapters(nn.Module):
241
+ def __init__(self, musicgen_model, processor, adapter_bottleneck_dim, device='cpu'):
242
+ super(MusicGenWithAdapters, self).__init__()
243
+ self.musicgen = musicgen_model
244
+
245
+ # Initialize the transformer-based adapter.
246
+ self.adapter = TransformerAdapter(
247
+ input_dim=32000,
248
+ bottleneck_dim=adapter_bottleneck_dim,
249
+ num_heads=4,
250
+ ff_dim=512,
251
+ dropout_prob=0.0
252
+ ).to(device)
253
+
254
+
255
+ def forward(self, audio_text):
256
+ encoder_output = self.musicgen.generate(**audio_text, max_new_tokens=128)
257
+
258
+ # Move encoder output to CPU for resampling.
259
+ encoder_output = encoder_output.to('cpu')
260
+ encoder_output = torchaudio.transforms.Resample(
261
+ orig_freq=encoder_output.size(2), new_freq=32000
262
+ )(encoder_output)
263
+
264
+ # Move back to device (using one of the adapter parameters for reference).
265
+ encoder_output = encoder_output.to(next(self.adapter.down_proj.parameters()).device)
266
+
267
+ # Expand from 1 channel to 2 channels if needed.
268
+ encoder_output = encoder_output.expand(-1, 2, -1)
269
+
270
+ # Pass through the transformer-based adapter.
271
+ adapted = self.adapter(encoder_output)
272
+ return adapted
273
+
274
+ #################################### Transformer Adapter class Ends here ############################
275
+ """
276
+
277
+
278
+
279
+
280
+
281
+
282
+ # Function to load the model based on the configuration
283
+ def load_model(use_finetuned_model, model_save_path, device):
284
+ if use_finetuned_model:
285
+ # Load the fine-tuned model (MusicGen + Adapters)
286
+ processor = AutoProcessor.from_pretrained(pretrained_model_name)
287
+ musicgen_model = MusicgenForConditionalGeneration.from_pretrained(pretrained_model_name).to(device)
288
+ model_with_adapters = MusicGenWithAdapters(musicgen_model, processor, adapter_bottleneck_dim=adapter_bottleneck_dim, device=device).to(device)
289
+
290
+ # Load the state dicts for both the MusicGen model and the adapter
291
+ checkpoint = torch.load(model_save_path, map_location=device)
292
+ model_with_adapters.musicgen.load_state_dict(checkpoint['musicgen_state_dict'])
293
+ model_with_adapters.adapter.load_state_dict(checkpoint['adapter_state_dict'])
294
+
295
+ model_with_adapters.eval()
296
+ total_params = sum(p.numel() for p in model_with_adapters.parameters())
297
+ print(f"Total number of parameters in the fine-tuned model: {total_params}")
298
+ return model_with_adapters, processor # Return processor
299
+ else:
300
+ # Load the pre-trained MusicGen model
301
+ processor = AutoProcessor.from_pretrained(pretrained_model_name)
302
+ musicgen_model = MusicgenForConditionalGeneration.from_pretrained(pretrained_model_name).to(device)
303
+ musicgen_model.eval()
304
+ total_params = sum(p.numel() for p in musicgen_model.parameters())
305
+ print(f"Total number of parameters in the Original model: {total_params}")
306
+ return musicgen_model, processor # Return processor
307
+
308
+ # Function to generate audio from a text prompt
309
+ def generate_audio(model, processor, text_prompt, sample_rate=32000):
310
+ # Generate input tensor for the text prompt
311
+ input_data = processor(text=[text_prompt], return_tensors="pt").to(device)
312
+
313
+ # Generate audio using the fine-tuned or pre-trained model
314
+ if isinstance(model, MusicGenWithAdapters):
315
+ musicgen = model.musicgen
316
+ else:
317
+ musicgen = model
318
+
319
+ with torch.no_grad():
320
+ generated_output = musicgen.generate(**input_data, max_new_tokens=max_new_tokens)
321
+
322
+ waveform = generated_output.squeeze(0).cpu()
323
+
324
+ if sample_rate != 32000:
325
+ resampler = torchaudio.transforms.Resample(orig_freq=32000, new_freq=sample_rate)
326
+ waveform = resampler(waveform)
327
+
328
+ return waveform
329
+
330
+ # Main inference code
331
+ if __name__ == "__main__":
332
+ # Load the appropriate model (pre-trained or fine-tuned) based on the setting
333
+ model, processor = load_model(use_finetuned_model, model_save_path, device)
334
+
335
+ # Read the metadata.jsonl file
336
+ metadata_df = pd.read_json(r'./GeneratedAudios/Makam/Prompts.json')
337
+
338
+ # Loop over each row in the JSONL file
339
+ for index, row in metadata_df.iterrows():
340
+ text_prompt = row['captions']
341
+ print(f"Generating audio for prompt: {text_prompt}")
342
+
343
+ # Generate audio
344
+ waveform = generate_audio(
345
+ model,
346
+ processor,
347
+ text_prompt,
348
+ sample_rate=sample_rate
349
+ )
350
+
351
+ # Prepare the output paths
352
+ output_audio_filename = os.path.basename(row['location'])
353
+ output_audio_path = os.path.join("./GeneratedAudios/Makam/CNN/", output_audio_filename)
354
+
355
+ # Ensure the output directory exists
356
+ os.makedirs(os.path.dirname(output_audio_path), exist_ok=True)
357
+
358
+ # Save the generated audio
359
+ torchaudio.save(output_audio_path, waveform, sample_rate)
360
+ print(f"Generated audio saved at {output_audio_path}")
361
+
362
+ # Save the waveform graph
363
+ AudioWaveform_graph_filename = os.path.splitext(output_audio_filename)[0] + '.jpeg'
364
+ AudioWaveform_graph_path = os.path.join("../Random/", AudioWaveform_graph_filename)
365
+
366
+ # Ensure the output directory exists
367
+ os.makedirs(os.path.dirname(AudioWaveform_graph_path), exist_ok=True)
368
+
369
+ plt.figure(figsize=(12, 4))
370
+ plt.plot(waveform.t().numpy())
371
+ plt.savefig(AudioWaveform_graph_path)
372
+ plt.close() # Close the figure to free memory
373
+ print(f"Waveform graph saved at {AudioWaveform_graph_path}")