0hawkeye33 commited on
Commit
64a2fa4
·
verified ·
1 Parent(s): 5f00a9c

Create Inference.py

Browse files
Files changed (1) hide show
  1. ISMIR/Adapters_2M/Inference.py +238 -0
ISMIR/Adapters_2M/Inference.py ADDED
@@ -0,0 +1,238 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
8
+ # Paths and configurations
9
+ pretrained_model_name = "facebook/musicgen-medium" # Pre-trained MusicGen model name
10
+ model_save_path = "./ModelsFinetuned/Hindustani_Adapter/ISMIR/MusicgenMedium_with_adapters_EncoderDecoder_512_CNN.pt" # Path to the fine-tuned model
11
+ output_audio_path = "./1.wav" # Path to save the generated audio
12
+ AudioWaveform_graph_path = "./1.jpeg" # Path to save the plot of generated audio
13
+ dropout_prob = 0.0 # Dropout probability in Adapter Layers
14
+ sample_rate = 32000 # Desired sample rate for the output audio
15
+ adapter_bottleneck_dim = 512 # Use the same dimension as training
16
+ max_new_tokens = 512 # To control length of music piece generated 512 = 10 sec
17
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
18
+
19
+ # Configuration to choose between pre-trained and fine-tuned model
20
+ use_finetuned_model = True # Set to True to use the fine-tuned model, False to use pre-trained model
21
+
22
+ """
23
+ # MultiLayer Perceptron
24
+ class Adapter(nn.Module):
25
+ def __init__(self, bottleneck_channels=256, input_channels=2, seq_len=32000): # input_channels=2
26
+ super(Adapter, self).__init__()
27
+
28
+ self.adapter_down = nn.Linear(seq_len, bottleneck_channels)
29
+ self.activation = nn.GELU()
30
+ self.adapter_up = nn.Linear(bottleneck_channels, seq_len)
31
+ self.dropout = nn.Dropout(p=dropout_prob)
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
+
39
+ return x.unsqueeze(1).expand(-1, 2, -1) # Expanding to 2 channels
40
+
41
+ """
42
+
43
+ # CNN Based
44
+ class Adapter(nn.Module):
45
+ def __init__(self, bottleneck_channels=192, input_channels=2, seq_len=32000, dropout_prob=0.1):
46
+ super(Adapter, self).__init__()
47
+
48
+ # Adapter Down: change kernel size from 5 to 7 (with padding=3 to maintain seq_len)
49
+ self.adapter_down = nn.Sequential(
50
+ nn.Conv1d(
51
+ in_channels=input_channels,
52
+ out_channels=bottleneck_channels,
53
+ kernel_size=7, # changed from 5 to 7
54
+ stride=1,
55
+ padding=3 # adjusted for kernel_size=7
56
+ ),
57
+ nn.BatchNorm1d(bottleneck_channels),
58
+ nn.GELU()
59
+ )
60
+
61
+ # Bottleneck: use 8 ResidualBlocks (each with kernel_size=7) instead of 6.
62
+ self.bottleneck = nn.Sequential(
63
+ ResidualBlock(bottleneck_channels, bottleneck_channels, kernel_size=7, dilation=1),
64
+ ResidualBlock(bottleneck_channels, bottleneck_channels, kernel_size=7, dilation=2),
65
+ ResidualBlock(bottleneck_channels, bottleneck_channels, kernel_size=7, dilation=4),
66
+ ResidualBlock(bottleneck_channels, bottleneck_channels, kernel_size=7, dilation=8),
67
+ ResidualBlock(bottleneck_channels, bottleneck_channels, kernel_size=7, dilation=16),
68
+ ResidualBlock(bottleneck_channels, bottleneck_channels, kernel_size=7, dilation=32),
69
+ ResidualBlock(bottleneck_channels, bottleneck_channels, kernel_size=7, dilation=64),
70
+ ResidualBlock(bottleneck_channels, bottleneck_channels, kernel_size=7, dilation=128),
71
+ ResidualBlock(bottleneck_channels, bottleneck_channels, kernel_size=7, dilation=256),
72
+ # Two extra ResidualBlocks to increase depth and parameters:
73
+ ResidualBlock(bottleneck_channels, bottleneck_channels, kernel_size=7, dilation=1),
74
+ ResidualBlock(bottleneck_channels, bottleneck_channels, kernel_size=7, dilation=2),
75
+ SEBlock(bottleneck_channels),
76
+ nn.Conv1d(bottleneck_channels, bottleneck_channels, kernel_size=3, stride=1, padding=1),
77
+ nn.BatchNorm1d(bottleneck_channels),
78
+ nn.GELU(),
79
+ )
80
+
81
+ # Adapter Up: also change kernel size from 5 to 7 (with padding=3)
82
+ self.adapter_up = nn.Sequential(
83
+ nn.Conv1d(
84
+ in_channels=bottleneck_channels,
85
+ out_channels=input_channels,
86
+ kernel_size=7, # changed from 5 to 7
87
+ stride=1,
88
+ padding=3 # adjusted for kernel_size=7
89
+ ),
90
+ nn.BatchNorm1d(input_channels)
91
+ )
92
+
93
+ self.dropout = nn.Dropout(p=dropout_prob)
94
+
95
+ def forward(self, residual):
96
+ x = self.adapter_down(residual)
97
+ x = self.bottleneck(x)
98
+ x = self.adapter_up(x)
99
+ x = self.dropout(x + residual) # residual connection
100
+ return x
101
+
102
+ class ResidualBlock(nn.Module):
103
+ def __init__(self, in_channels, out_channels, kernel_size=7, stride=1, dilation=1):
104
+ super(ResidualBlock, self).__init__()
105
+
106
+ # The larger kernel size increases parameter count.
107
+ self.conv1 = nn.Conv1d(
108
+ in_channels, out_channels, kernel_size, stride,
109
+ padding=(kernel_size // 2) * dilation, dilation=dilation
110
+ )
111
+ self.bn1 = nn.BatchNorm1d(out_channels)
112
+ self.activation = nn.GELU()
113
+
114
+ self.conv2 = nn.Conv1d(
115
+ out_channels, out_channels, kernel_size, stride,
116
+ padding=(kernel_size // 2) * dilation, dilation=dilation
117
+ )
118
+ self.bn2 = nn.BatchNorm1d(out_channels)
119
+
120
+ self.layer_norm = nn.LayerNorm(out_channels)
121
+
122
+ def forward(self, x):
123
+ residual = x # Preserve input for the skip connection
124
+ x = self.conv1(x)
125
+ x = self.bn1(x)
126
+ x = self.activation(x)
127
+ x = self.conv2(x)
128
+ x = self.bn2(x)
129
+ x = x + residual # Skip connection
130
+ return x
131
+
132
+ class SEBlock(nn.Module):
133
+ def __init__(self, channels, reduction=8):
134
+ super(SEBlock, self).__init__()
135
+ self.global_avg_pool = nn.AdaptiveAvgPool1d(1) # Squeeze
136
+ self.fc = nn.Sequential(
137
+ nn.Linear(channels, channels // reduction),
138
+ nn.ReLU(),
139
+ nn.Linear(channels // reduction, channels),
140
+ nn.Sigmoid()
141
+ )
142
+
143
+ def forward(self, x):
144
+ batch_size, channels, _ = x.shape
145
+ y = self.global_avg_pool(x).view(batch_size, channels)
146
+ y = self.fc(y).view(batch_size, channels, 1)
147
+ return x * y # Scale input features based on channel attention
148
+
149
+
150
+ # MusicGen Model with Adapter (same as in training)
151
+ class MusicGenWithAdapters(nn.Module):
152
+ def __init__(self, musicgen_model, processor, adapter_bottleneck_dim=32, device='cpu'):
153
+ super(MusicGenWithAdapters, self).__init__()
154
+ self.musicgen = musicgen_model
155
+ self.adapter = Adapter(bottleneck_channels=adapter_bottleneck_dim, input_channels=2, seq_len=32000).to(device)
156
+
157
+ def forward(self, audio_text):
158
+ encoder_output = self.musicgen.generate(**audio_text, max_new_tokens=max_new_tokens)
159
+ encoder_output = encoder_output.to('cpu')
160
+ encoder_output = torchaudio.transforms.Resample(orig_freq=encoder_output.size(2), new_freq=32000)(encoder_output)
161
+ encoder_output = encoder_output.to(self.adapter.adapter_down.weight.device)
162
+ adapted = self.adapter(encoder_output)
163
+ return adapted
164
+
165
+ # Function to load the model based on the configuration
166
+ def load_model(use_finetuned_model, model_save_path, device):
167
+ if use_finetuned_model:
168
+ # Load the fine-tuned model (MusicGen + Adapters)
169
+ processor = AutoProcessor.from_pretrained(pretrained_model_name)
170
+ musicgen_model = MusicgenForConditionalGeneration.from_pretrained(pretrained_model_name).to(device)
171
+ model_with_adapters = MusicGenWithAdapters(musicgen_model, processor, adapter_bottleneck_dim=adapter_bottleneck_dim, device=device).to(device)
172
+
173
+ # Load the state dicts for both the MusicGen model and the adapter
174
+ checkpoint = torch.load(model_save_path, map_location=device)
175
+ model_with_adapters.musicgen.load_state_dict(checkpoint['musicgen_state_dict'])
176
+ model_with_adapters.adapter.load_state_dict(checkpoint['adapter_state_dict'])
177
+
178
+ model_with_adapters.eval()
179
+ total_params = sum(p.numel() for p in model_with_adapters.parameters())
180
+ print(f"Total number of parameters in the fine-tuned model: {total_params}")
181
+ return model_with_adapters
182
+ else:
183
+ # Load the pre-trained MusicGen model
184
+ musicgen_model = MusicgenForConditionalGeneration.from_pretrained(pretrained_model_name).to(device)
185
+ musicgen_model.eval()
186
+ total_params = sum(p.numel() for p in musicgen_model.parameters())
187
+ print(f"Total number of parameters in the Original model: {total_params}")
188
+ return musicgen_model
189
+
190
+ # Function to generate audio from a text prompt
191
+ def generate_audio(model, text_prompt, sample_rate=32000):
192
+ processor = AutoProcessor.from_pretrained(pretrained_model_name)
193
+
194
+ # Generate input tensor for the text prompt
195
+ input_data = processor(text=[text_prompt], return_tensors="pt").to(device)
196
+
197
+ # Generate audio using the fine-tuned or pre-trained model
198
+ if isinstance(model, MusicGenWithAdapters):
199
+ musicgen = model.musicgen
200
+ else:
201
+ musicgen = model
202
+
203
+ with torch.no_grad():
204
+ generated_output = musicgen.generate(**input_data, max_new_tokens=max_new_tokens)
205
+
206
+ waveform = generated_output.squeeze(0).cpu()
207
+
208
+ if sample_rate != 32000:
209
+ resampler = torchaudio.transforms.Resample(orig_freq=32000, new_freq=sample_rate)
210
+ waveform = resampler(waveform)
211
+
212
+ return waveform
213
+
214
+ # Main inference code
215
+ if __name__ == "__main__":
216
+ # Get text prompt from the user
217
+ text_prompt = input("Enter a text prompt for music generation: ")
218
+
219
+ # Load the appropriate model (pre-trained or fine-tuned) based on the setting
220
+ model = load_model(use_finetuned_model, model_save_path, device)
221
+
222
+ # Generate audio
223
+ waveform = generate_audio(
224
+ model,
225
+ text_prompt,
226
+ sample_rate=sample_rate
227
+ )
228
+
229
+ # Save the generated audio
230
+ torchaudio.save(output_audio_path, waveform, sample_rate)
231
+ print(f"Generated audio saved at {output_audio_path}")
232
+
233
+ # Optional: Visualize the waveform
234
+ plt.figure(figsize=(12, 4))
235
+ plt.plot(waveform.t().numpy())
236
+ plt.savefig(AudioWaveform_graph_path)
237
+ plt.show()
238
+ print(f"Waveform graph saved at {AudioWaveform_graph_path}")